La possibilità di eseguire query sulle dimensioni in linea di un elemento principale e sui valori delle unità di query del contenitore ha recentemente raggiunto il supporto stabile in tutti i motori dei browser moderni.
Tuttavia, la specifica di contenimento include più di semplici query sulle dimensioni; consente anche di eseguire query sui valori di stile di un elemento principale. A partire da Chromium 111, potrai applicare il contenimento degli stili per i valori delle proprietà personalizzate e eseguire query su un elemento principale per il valore di una proprietà personalizzata.
Ciò significa che abbiamo un controllo ancora più logico degli stili in CSS e consente una separazione migliore del livello di logica e dati di un'applicazione dai suoi stili.
La specifica del Modulo di contenimento CSS di Livello 3, che riguarda le query su dimensioni e stili, consente di eseguire query su qualsiasi stile da un elemento principale, incluse coppie di proprietà e valori come font-weight: 800
. Tuttavia, nel lancio di questa funzionalità, al momento le query di stile funzionano solo con i valori delle proprietà personalizzate CSS. Questa operazione è ancora molto utile per combinare gli stili e separare i dati dal design. Vediamo come utilizzare le query di stile con le proprietà CSS personalizzate:
Guida introduttiva alle query di stile
Supponiamo di avere il seguente codice HTML:
<ul class="card-list">
<li class="card-container">
<div class="card">
...
</div>
</li>
</ul>
Per utilizzare query di stile, devi prima configurare un elemento contenitore. Questo richiede un approccio leggermente diverso a seconda che tu stia eseguendo una query su un account principale diretto o indiretto.
Eseguire query sui gruppi di primo livello
A differenza delle query sugli stili, non è necessario applicare il contenimento utilizzando la proprietà container-type
o container
a .card-container
affinché .card
possa eseguire query sugli stili del suo elemento principale diretto. Tuttavia, dobbiamo applicare gli stili (in questo caso valori delle proprietà personalizzate) a un contenitore (in questo caso .card-container
) o a qualsiasi elemento che contenga l'elemento a cui vogliamo applicare lo stile nel DOM. Non possiamo applicare gli stili a cui stiamo interrogando sull'elemento diretto a cui stiamo definendo utilizzando tale query perché ciò potrebbe causare loop infiniti.
Per eseguire una query direttamente a un genitore, puoi scrivere:
/* styling .card based on the value of --theme on .card-container */
@container style(--theme: warm) {
.card {
background-color: wheat;
border-color: brown;
...
}
}
Potresti aver notato che la query di stile inserisce la query tra style()
. Questo serve a distinguere i valori delle taglie dagli stili. Ad esempio, puoi scrivere una query per la larghezza del contenitore come @container (min-width: 200px) { … }
. Gli stili verranno applicati se il contenitore principale ha una larghezza di almeno 200 px. Tuttavia, min-width
può essere anche una proprietà CSS e puoi eseguire una query per il valore CSS di min-width
utilizzando le query di stile. Ecco perché dovresti utilizzare il wrapper style()
per chiarire la differenza: @container style(min-width: 200px) { … }
.
Stili dei genitori non diretti
Se vuoi eseguire query sugli stili per qualsiasi elemento che non sia un elemento principale diretto, devi assegnare a quell'elemento un container-name
. Ad esempio, possiamo applicare stili a .card
in base agli stili di .card-list
assegnando a .card-list
un container-name
e facendovi riferimento nella query di stile.
/* styling .card based on the value of --moreGlobalVar on .card-list */
@container cards style(--moreGlobalVar: value) {
.card {
...
}
}
In genere, è buona norma assegnare un nome ai contenitori per chiarire su cosa stai eseguendo una query e per poter accedere più facilmente a questi contenitori. Ciò può risultare utile ad esempio se vuoi applicare uno stile diretto agli elementi all'interno di .card
. Senza un contenitore denominato su .card-container
, non possono eseguire query direttamente.
Ma tutto questo ha molto più senso nella pratica. Vediamo alcuni esempi:
Query di stile in azione
Le query sugli stili sono particolarmente utili quando hai un componente riutilizzabile con più varianti o quando non hai il controllo su tutti gli stili, ma devi applicare modifiche in alcuni casi. Questo esempio mostra un insieme di schede di prodotto che condividono lo stesso componente della scheda. Alcune schede di prodotto contengono dettagli/note aggiuntive, come "Nuovo" o "Disponibilità limitata", attivate da una proprietà personalizzata denominata --detail
. Inoltre, se un prodotto è in "Disponibile in quantità limitata", viene visualizzato un bordo di sfondo rosso scuro. È probabile che questo tipo di informazioni venga visualizzato sul server e possa essere applicato alle schede tramite stili in linea come segue:
<div class="product-list">
<div class="product-card-container" style="--detail: new">
<div class="product-card">
<div class="media">
<img .../>
<div class="comment-block"></div>
</div>
</div>
<div class="meta">
...
</div>
</div>
<div class="product-card-container" style="--detail: low-stock">
...
</div>
<div class="product-card-container">
...
</div>
...
</div>
Dati questi dati strutturati, puoi passare valori a --detail
e utilizzare questa proprietà CSS personalizzata per applicare gli stili:
@container style(--detail: new) {
.comment-block {
display: block;
}
.comment-block::after {
content: 'New';
border: 1px solid currentColor;
background: white;
...
}
}
@container style(--detail: low-stock) {
.comment-block {
display: block;
}
.comment-block::after {
content: 'Low Stock';
border: 1px solid currentColor;
background: white;
...
}
.media-img {
border: 2px solid brickred;
}
}
Il codice riportato sopra ci consente di applicare un chip per --detail: low-stock
e --detail: new
, ma potresti aver notato una certa ridondanza nel blocco di codice. Al momento, non è possibile eseguire query solo per la presenza di --detail
con @container style(--detail)
, il che consentirebbe una migliore condivisione degli stili e meno ripetizioni. Questa funzionalità è attualmente in discussione nel gruppo di lavoro.
Schede meteo
L'esempio precedente utilizzava una singola proprietà personalizzata con più valori possibili per applicare gli stili. Tuttavia, puoi anche utilizzare e eseguire query su più proprietà personalizzate. Considera questo esempio di scheda meteo:
Per applicare uno stile ai gradienti di sfondo e alle icone di queste schede, cerca le caratteristiche del meteo, ad esempio "nuvoloso", "piovoso" o "soleggiato":
@container style(--sunny: true) {
.weather-card {
background: linear-gradient(-30deg, yellow, orange);
}
.weather-card:after {
content: url(<data-uri-for-demo-brevity>);
background: gold;
}
}
In questo modo, puoi applicare uno stile a ogni scheda in base alle sue caratteristiche uniche. Tuttavia, puoi anche applicare uno stile alle combinazioni di caratteristiche (proprietà personalizzate) utilizzando il combinatore and
nello stesso modo delle query sui media. Ad esempio, una giornata nuvolosa e soleggiata avrà il seguente aspetto:
@container style(--sunny: true) and style(--cloudy: true) {
.weather-card {
background: linear-gradient(24deg, pink, violet);
}
.weather-card:after {
content: url(<data-uri-for-demo-brevity>);
background: violet;
}
}
Separazione dei dati dal design
In entrambe le demo, esiste un vantaggio strutturale della separazione del livello dati (DOM che verrà visualizzato nella pagina) dagli stili applicati. Gli stili sono scritti come possibili varianti all'interno dello stile dei componenti, mentre un endpoint potrebbe inviare i dati che verranno poi utilizzati per applicare lo stile al componente. Puoi utilizzare un singolo valore, come nel primo caso, l'aggiornamento del valore --detail
, oppure più variabili, come nel secondo caso (impostando --rainy
, --cloudy
o --sunny
. E la parte migliore è che puoi combinare anche questi valori. Se controlli sia --sunny
che --cloudy
, potresti mostrare uno stile parzialmente nuvoloso.
L'aggiornamento dei valori delle proprietà personalizzate tramite JavaScript può essere eseguito agevolmente durante la configurazione del modello DOM (ovvero durante la creazione del componente in un framework) oppure può essere aggiornato in qualsiasi momento mediante <parentElem>.style.setProperty('--myProperty’, <value>)
. I
Ecco una demo che con poche righe di codice aggiorna il --theme
di un pulsante e applica gli stili utilizzando query di stile e la proprietà personalizzata (--theme
):
Personalizza la scheda utilizzando le query di stile. Il codice JavaScript utilizzato per aggiornare i valori delle proprietà personalizzate è:
const themePicker = document.querySelector('#theme-picker')
const btnParent = document.querySelector('.btn-section');
themePicker.addEventListener('input', (e) => {
btnParent.style.setProperty('--theme', e.target.value);
})
Le funzionalità descritte in questo articolo sono solo l'inizio. Puoi aspettarti di più dalle query dei contenitori per aiutarti a creare interfacce dinamiche e reattive. Per quanto riguarda nello specifico le query di stile, ci sono ancora alcuni problemi da risolvere. Una è l'implementazione di query sugli stili per gli stili CSS oltre alle proprietà personalizzate. Questo fa già parte del livello di specifiche attuale, ma non è ancora implementato in nessun browser. La valutazione del contesto booleano dovrebbe essere aggiunta al livello attuale della specifica quando il problema in sospeso sarà risolto, mentre la query sull'intervallo è prevista per il livello successivo della specifica.