⌨️ Sviluppo web

Container queries CSS: componenti davvero responsive

Le container queries adattano un componente allo spazio del contenitore e non alla finestra: sintassi, unità cqi e quando preferirle alle media query.

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-scheme o prefers-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-size e si scrive la regola con @container.
  • Le unità cqi e 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.
MM
Marco Marzaduri

Marco Marzaduri si occupa di cybersecurity, informatica forense e sviluppo web. Laureato in informatica, unisce il rigore dell'analisi tecnica all'attenzione per le persone che usano la tecnologia.

Leggi anche