Migrare a container query e :has() senza introdurre debito
Quando una funzione CSS moderna riduce la complessità del front-end e quando la aumenta: quattro casi e una checklist per la code review.
Molti team stanno sostituendo JavaScript e vecchi accorgimenti con container query, :has() e cascade layers. Il codice di ogni singolo file diventa più corto, e sembra un guadagno netto. Il 3 novembre 2026 Gabriel Shoyombo ha pubblicato su Smashing Magazine un approfondimento che mette in dubbio questa conclusione.
La distinzione di partenza è tra semplicità locale, cioè meno codice in un file, e complessità di sistema, cioè quante interazioni bisogna capire prima di modificare l'app. Una nuova funzione CSS riduce la complessità solo se sostituisce del tutto l'implementazione precedente. Sono quattro i casi che l'autore porta a sostegno, e una checklist finale da usare nelle code review.
Quando un comportamento ha due proprietari
Il primo scenario riguarda un ResizeObserver che attivava una classe al variare della larghezza. È stato sostituito da una container query, ma l'osservatore e le regole vecchie sono rimasti nel codice. Il comportamento ha così due proprietari.
Il problema emerge quando si cambia il breakpoint da 480 a 600px: le card finiscono in uno stato non voluto tra i due valori, perché una parte del codice risponde alla nuova soglia e l'altra alla vecchia. La migrazione, in pratica, non era finita.
Perché un container può collassare a zero
Il secondo caso riguarda container-type: inline-size, che crea un block formatting context e applica inline-size containment. Nei test dell'autore tre card, larghe 74, 96 e 114px, sono collassate a 0px in contesti flex, float e inline-block.
.card {
container-type: inline-size;
}
Dichiarare un container non è quindi un'operazione neutra: cambia il comportamento del layout attorno al componente. Lo notano anche i designer che definiscono componenti responsive, perché il comportamento dei container influisce sul layout circostante.
Come :has() vince per specificità senza che ce ne si accorga
Nel terzo scenario un selettore con :has() ha colpito elementi di una card priva di immagine. La regola era questa:
.card:has(img) p
Il selettore ha vinto per specificità, 0-1-2 contro 0-1-1, e ha quindi sovrascritto regole che sembravano più precise. I rimedi indicati sono tre: usare i combinatori figlio, ricorrere a :where() per azzerare la specificità, e fare attenzione ai cascade layers.
Quanto può costare :has() in termini di prestazioni
L'ultimo caso è una misura. In Chrome 153 su Mac, a ottobre 2026, su una lista di 5.000 righe una regola :has() ancorata a body costava circa 1,4ms con un elemento ristilizzato. Combinata con una seconda regola saliva a circa 7ms con 5.001 elementi, e con 20.000 righe a circa 31ms per toggle.
I limiti vanno detti con chiarezza. I dati vengono da una sola pagina, un solo browser e una sola macchina, e l'autore stesso li definisce illustrativi. Il comportamento di restyling in Chromium non è spiegato ed è stato segnalato con una issue, mentre l'esempio con CSS-in-JS è soltanto un confronto di contorno. Non è un'indicazione che il CSS moderno sia da evitare.
Le sei domande da fare in code review
L'articolo chiude con una checklist che si presta a una revisione di migrazione. Le domande riguardano:
- la proprietà: chi possiede il comportamento, una sola regola o più parti del codice;
- l'ambito: quali elementi la regola può raggiungere davvero;
- la cascata: come interagiscono specificità e layer;
- la completezza della migrazione: se la vecchia implementazione è stata rimossa del tutto;
- le prestazioni: se sono state misurate e non soltanto supposte;
- la manutenibilità: se chi arriva dopo capisce quante cose deve tenere insieme.
Container query e :has() conviene adottarle quando la migrazione si chiude, cioè quando il codice precedente sparisce e la regola nuova ha un solo proprietario. Quando la vecchia implementazione resta in piedi accanto alla nuova, il guadagno locale diventa un costo di sistema.
Fonti
- Smashing Magazine, “Modern CSS Might Make Your Front-End More Complex”, Gabriel Shoyombo, 3 novembre 2026