Guida introduttiva alle query Stili

La possibilità di eseguire query sulla dimensione in linea di un elemento principale e sui valori delle unità di query container ha recentemente raggiunto il supporto stabile in tutti i motori dei browser moderni.

Browser Support

  • Chrome: 105.
  • Edge: 105.
  • Firefox: 110.
  • Safari: 16.

Source

Tuttavia, la specifica di contenimento include non solo le query sulle dimensioni, ma consente anche di eseguire query sui valori di stile di un elemento principale. A partire da Chromium 111, potrai applicare il contenimento dello stile ai valori delle proprietà personalizzate ed eseguire query su un elemento principale per il valore di una proprietà personalizzata.

Browser Support

  • Chrome: 111.
  • Edge: 111.
  • Firefox: 151.
  • Safari: 18.

Ciò significa che abbiamo un controllo ancora più logico degli stili in CSS e consente una migliore separazione del livello di logica e dati di un'applicazione dai relativi stili.

La specifica del modulo di contenimento CSS livello 3, che copre le query sulle dimensioni e sullo stile, consente di eseguire query su tutti gli stili di un elemento principale, incluse le coppie proprietà-valore come font-weight: 800. Tuttavia, durante l'implementazione di questa funzionalità, le query sullo stile al momento funzionano solo con i valori delle proprietà personalizzate CSS. Questa funzionalità è comunque molto utile per combinare gli stili e separare i dati dal design. Vediamo come utilizzare le query sullo stile con le proprietà personalizzate CSS:

Guida introduttiva alle query sullo stile

Supponiamo di avere il seguente codice HTML:

<ul class="card-list">
  <li class="card-container">
    <div class="card">
      ...
    </div>
  </li>
</ul>

Per utilizzare le query sullo stile, devi prima configurare un elemento container. Questo richiede un approccio leggermente diverso a seconda che tu stia eseguendo query su un elemento principale diretto o indiretto.

Eseguire query sugli elementi principali diretti

Diagramma di una query di stile.

A differenza delle query sulle dimensioni, non è necessario applicare il contenimento utilizzando la proprietà container-type o container a .card-container affinché .card possa eseguire query sugli stili del relativo elemento principale diretto. Tuttavia, dobbiamo applicare gli stili (in questo caso i valori delle proprietà personalizzate) a un container (in questo caso .card-container) o a qualsiasi elemento contenente l'elemento a cui stiamo applicando lo stile nel DOM. Non possiamo applicare gli stili di cui stiamo eseguendo query all'elemento diretto a cui stiamo applicando lo stile utilizzando la query, perché ciò potrebbe causare loop infiniti.

Per eseguire query direttamente su un elemento principale, puoi scrivere:

/* styling .card based on the value of --theme on .card-container */
@container style(--theme: warm) {
  .card {
    background-color: wheat;
    border-color: brown; 
    ...
  }
}

Avrai notato che la query sullo stile racchiude la query con style(). Questo serve a distinguere i valori delle dimensioni dagli stili. Ad esempio, puoi scrivere una query per la larghezza del container come @container (min-width: 200px) { … }. In questo modo, gli stili verranno applicati se il container principale ha una larghezza di almeno 200 px. Tuttavia, min-width può anche essere una proprietà CSS e puoi eseguire query sul valore CSS di min-width utilizzando le query sullo stile. Ecco perché utilizzeresti il wrapper style() per rendere chiara la differenza: @container style(min-width: 200px) { … }.

Applicare lo stile agli elementi principali non diretti

Se vuoi eseguire query sugli stili di un elemento che non è un elemento principale diretto, devi assegnare a quell'elemento un container-name. Ad esempio, possiamo applicare gli stili a .card in base agli stili di .card-list assegnando a .card-list un container-name e facendo riferimento a questo nella query sullo stile.

/* styling .card based on the value of --moreGlobalVar on .card-list */
@container cards style(--moreGlobalVar: value) {
  .card {
    ...
  }
}

In genere, è una best practice assegnare nomi ai container per rendere chiaro su cosa stai eseguendo query e sbloccare la possibilità di accedere più facilmente a questi container. Un esempio in cui questa funzionalità è utile è quando vuoi applicare lo stile direttamente agli elementi all'interno di .card. Senza un container denominato in .card-container, non possono eseguire query direttamente su di esso.

Ma tutto questo ha molto più senso nella pratica. Diamo un'occhiata ad alcuni esempi:

Query sullo stile in azione

Immagine dimostrativa con più schede di prodotto, alcune con i tag &quot;Nuovo&quot; o &quot;Scorte limitate&quot; e la scheda &quot;Scorte limitate&quot; con sfondo rosso.

Le query sullo stile sono particolarmente utili quando hai un componente riutilizzabile con più varianti o quando non hai il controllo di tutti gli stili, ma devi applicare modifiche in determinati casi. Questo esempio mostra un insieme di schede di prodotto che condividono lo stesso componente della scheda. Alcune schede di prodotto hanno dettagli/note aggiuntive, ad esempio "Nuovo" o "Scorte limitate", attivate da una proprietà personalizzata denominata --detail. Inoltre, se un prodotto ha "Scorte limitate", viene visualizzato uno sfondo con bordo rosso scuro. Questo tipo di informazioni viene probabilmente sottoposto a rendering lato server e può 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 i valori a --detail e utilizzare questa proprietà personalizzata CSS 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 sulla presenza di --detail con @container style(--detail), il che consentirebbe una migliore condivisione degli stili e una minore ripetizione. Questa funzionalità è attualmente in fase di 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 ed eseguire query su più proprietà personalizzate. Prendiamo come esempio questa scheda meteo:

Demo delle schede meteo.

Per applicare lo stile alle sfumature di sfondo e alle icone di queste schede, cerca le caratteristiche meteorologiche, 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 lo stile a ogni scheda in base alle sue caratteristiche uniche. Tuttavia, puoi anche applicare lo stile alle combinazioni di caratteristiche (proprietà personalizzate) utilizzando il and combinatore nello stesso modo delle query supporti. Ad esempio, un giorno nuvoloso e soleggiato avrebbe 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;
  }
}

Separare i dati dal design

In entrambe queste demo, la separazione del livello di dati (DOM che verrà sottoposto a rendering nella pagina) dagli stili applicati offre un vantaggio strutturale. Gli stili vengono scritti come possibili varianti che risiedono nello 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, aggiornando il valore --detail, o più variabili, come nel secondo caso (impostando --rainy, --cloudy o --sunny. La cosa migliore è che puoi anche combinare questi valori. Se controlli sia --sunny sia --cloudy, potresti visualizzare uno stile parzialmente nuvoloso.

L'aggiornamento dei valori delle proprietà personalizzate tramite JavaScript può essere eseguito senza problemi, sia durante la configurazione del modello DOM (ovvero durante la creazione del componente in un framework) sia in qualsiasi momento utilizzando <parentElem>.style.setProperty('--myProperty’, <value>). I

Ecco una demo che, in poche righe di codice, aggiorna --theme di un pulsante e applica gli stili utilizzando le query sullo stile e la proprietà personalizzata (--theme):

Per applicare lo stile alla scheda utilizzando le query sullo stile, il codice JavaScript utilizzato per aggiornare i valori delle proprietà personalizzate è il seguente:

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 altre funzionalità dalle query sui container per aiutarti a creare interfacce dinamiche e responsive. Per quanto riguarda le query sullo stile in particolare, ci sono ancora alcuni problemi aperti. Uno è l'implementazione delle query sullo stile per gli stili CSS oltre alle proprietà personalizzate. Questa funzionalità fa già parte del livello di specifica corrente, ma non è ancora implementata in nessun browser. La valutazione del contesto booleano dovrebbe essere aggiunta al livello di specifica corrente quando il problema in sospeso viene risolto, mentre le query sull'intervallo sono pianificate per il livello successivo della specifica.