Le media query hanno reso possibile il web responsive, ma hanno un limite strutturale: rispondono alla larghezza della finestra, non a quella dello spazio in cui un componente si trova. Una scheda prodotto può comparire larga nella pagina principale e stretta in una barra laterale, sullo stesso schermo. Con le sole media query sei costretto a scrivere varianti specifiche per ogni posizione. Le container queries risolvono il problema: il componente si adatta al proprio contenitore, ovunque venga inserito.
Il problema in un esempio
Immagina una scheda con immagine e testo. Quando c'è spazio, vuoi immagine a sinistra e testo a destra; quando lo spazio è poco, immagine sopra e testo sotto. Con una media query scriveresti:
@media (min-width: 800px) {
.card { display: flex; }
}
Ma se a 1200 pixel di finestra la scheda finisce in una colonna laterale larga 300 pixel, verrà comunque disposta in orizzontale, schiacciata e illeggibile. La finestra è larga, il contenitore no.
Dichiarare un contenitore
Per usare le container queries devi prima indicare quale elemento fa da contenitore di riferimento, con la proprietà container-type:
.card-wrapper {
container-type: inline-size;
}
Il valore inline-size dice al browser di tenere traccia della dimensione sull'asse in linea, cioè la larghezza nella scrittura orizzontale. Esiste anche size, che considera entrambe le dimensioni, ma richiede che l'altezza del contenitore non dipenda dal contenuto, quindi nella pratica si usa quasi sempre inline-size.
Poi scrivi la regola con @container:
.card {
display: grid;
gap: 1rem;
}
@container (min-width: 420px) {
.card {
grid-template-columns: 160px 1fr;
}
}
Ora la scheda si dispone in orizzontale solo quando il suo contenitore supera i 420 pixel, indipendentemente dalla larghezza della finestra.
Una regola importante
Un elemento non può interrogare sé stesso: la query si riferisce sempre all'antenato più vicino che sia stato dichiarato contenitore. Per questo si usa spesso un elemento avvolgente (il card-wrapper dell'esempio) oppure si dichiara contenitore la colonna o la cella di griglia in cui il componente viene inserito.
Contenitori con nome
Quando ci sono contenitori annidati, puoi assegnare un nome e interrogare proprio quello:
.sidebar {
container-type: inline-size;
container-name: sidebar;
}
/* scorciatoia equivalente */
.main {
container: main / inline-size;
}
@container sidebar (max-width: 300px) {
.widget-title { font-size: 1rem; }
}
Senza nome, la query guarda il contenitore più vicino; con il nome, salta quelli intermedi.
Le unità relative al contenitore
Insieme alle query sono arrivate nuove unità di misura che si riferiscono al contenitore:
| Unità | Significato |
|---|---|
cqi |
1% della dimensione in linea del contenitore |
cqb |
1% della dimensione di blocco del contenitore |
cqw / cqh |
1% di larghezza / altezza del contenitore |
cqmin / cqmax |
il minore / maggiore tra cqi e cqb |
Sono utilissime per una tipografia che scala con il componente:
.card h3 {
font-size: clamp(1rem, 4cqi, 1.6rem);
}
Il titolo cresce con la larghezza della scheda, ma resta entro un minimo e un massimo leggibili.
Media query o container query?
Non si tratta di sostituire le une con le altre. Ognuna ha il suo ambito:
- Media query per decisioni che riguardano davvero la pagina e il dispositivo: layout generale, numero di colonne principali, preferenze dell'utente come
prefers-color-schemeoprefers-reduced-motion, orientamento, stampa. - Container query per i componenti riutilizzabili: schede, widget, moduli, elementi di un sistema di design che possono finire in contesti diversi.
Una buona regola: la struttura della pagina la decide la finestra, l'aspetto del componente lo decide il suo spazio.
Effetti collaterali da conoscere
Dichiarare container-type: inline-size attiva un contenimento della dimensione in linea: il contenitore non può più ricavare la propria larghezza dai figli. Di solito non è un problema per blocchi che occupano tutta la larghezza disponibile, ma un elemento che dovrebbe essere largo "quanto il suo contenuto", come un elemento inline-block o un elemento flex senza dimensione definita, può collassare a larghezza zero. Se dopo aver aggiunto container-type qualcosa sparisce, controlla prima di tutto questo.
Inoltre, la proprietà va applicata con criterio: dichiarare contenitore ogni elemento della pagina non serve e rende più difficile capire quale contenitore stia rispondendo a una query.
Supporto e strategia
Le container queries basate sulla dimensione sono supportate da tutti i principali browser aggiornati. Se devi garantire una resa accettabile anche su browser molto vecchi, scrivi lo stile di base per lo spazio più piccolo (impilato, a una colonna) e usa @container per arricchirlo: chi non le supporta vedrà comunque una versione funzionante.
Esistono anche le style queries, che interrogano il valore di una custom property del contenitore, per esempio @container style(--variante: compatta). Il supporto è meno uniforme, quindi conviene trattarle come un miglioramento progressivo.
In sintesi
- Le container queries adattano un componente allo spazio del suo contenitore, non alla finestra.
- Si dichiara il contenitore con
container-type: inline-sizee si scrive la regola con@container. - Le unità
cqie simili permettono tipografia e spaziature proporzionate al componente. - Le media query restano lo strumento giusto per il layout di pagina e le preferenze dell'utente.
- Il contenimento può far collassare elementi senza larghezza definita: verificalo subito.