Guida introduttiva alle query Stili

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

Supporto dei browser

  • 105
  • 105
  • 110
  • 16

Origine

Tuttavia, la specifica di contenimento include molto più che semplici query sulle dimensioni, ma consente anche di eseguire query sui valori di stile di un elemento padre. Da Chromium 111 potrai applicare il contenimento dello stile per i valori delle proprietà personalizzate ed eseguire query su un elemento principale per conoscere il valore di una proprietà personalizzata.

Supporto dei browser

  • 111
  • 111
  • x
  • x

Origine

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

La specifica di livello 3 del modulo di contenimento CSS, che riguarda le query su dimensioni e stile, consente di eseguire query su qualsiasi stile da un elemento padre, incluse coppie di proprietà e valori come font-weight: 800. Tuttavia, al momento, durante l'implementazione di questa funzionalità, le query di stile funzionano solo con i valori delle proprietà personalizzate CSS. Ciò è comunque molto utile per combinare gli stili e separare i dati dalla progettazione. Diamo un'occhiata a come utilizzare le query di stile con le proprietà personalizzate CSS:

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. Ciò richiede un approccio leggermente diverso, a seconda che si stia eseguendo una query su un elemento principale diretto o indiretto.

Esecuzione di query su elementi padre diretti

Diagramma di una query di stile.

A differenza delle query di stile, non è necessario applicare il contenimento utilizzando la proprietà container-type o container a .card-container affinché .card sia in grado di eseguire query sugli stili dell'elemento principale diretto. Tuttavia, dobbiamo applicare gli stili (in questo caso i valori delle proprietà personalizzate) a un contenitore (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 a cui stiamo query sull'elemento diretto a cui stiamo definendo utilizzando tale query perché ciò potrebbe causare loop infiniti.

Per eseguire una query direttamente su 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; 
    ...
  }
}

Avrai notato che la query di stile aggrega 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 vengono applicati gli stili se il contenitore principale è largo almeno 200 px. Tuttavia, min-width può anche essere una proprietà CSS e puoi eseguire query per il valore CSS di min-width utilizzando 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 una query sugli stili per qualsiasi elemento che non è 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, una best practice consiste nel assegnare un nome ai container per chiarire su cosa stai eseguendo query e per sbloccare la possibilità di accedervi più facilmente. Ciò può risultare utile ad esempio se vuoi applicare uno stile diretto agli elementi all'interno di .card. Senza un container denominato su .card-container, non possono eseguire query direttamente.

Ma tutto questo ha molto più senso nella pratica. Vediamo qualche esempio:

Applica uno stile alle query

Immagine demo con più schede di prodotto, alcune con tag &quot;nuovo&quot; o &quot;disponibilità limitata&quot; e la scheda &quot;disponibilità limitata&quot; con uno sfondo rosso.

Le query di stile 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. Alcune schede di prodotto contengono note/dettagli aggiuntivi, come "Nuovo" o "Disponibilità in esaurimento", attivati da una proprietà personalizzata denominata --detail. Inoltre, se un prodotto è in "Bassa disponibilità", il bordo diventa rosso scuro. Questo tipo di informazioni viene probabilmente visualizzato dal server e può essere applicato alle schede tramite stili in linea, ad esempio:

 <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 strutturati, puoi trasmettere 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 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 mischiarli utilizzando anche più proprietà personalizzate ed eseguendo query. Considera questo esempio di scheda meteo:

Demo delle schede meteo.

Per definire i gradienti di sfondo e le icone di queste schede, cerca le caratteristiche meteorologiche, ad esempio "nuvoloso", "piovoso" o "solato":

@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 definire lo stile di ogni scheda in base alle sue caratteristiche uniche. Puoi anche definire combinazioni di caratteristiche (proprietà personalizzate), utilizzando il combinatore and come per le query multimediali. Ad esempio, una giornata sia nuvolosa che soleggiata potrebbe essere:

@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 dalla progettazione

In entrambe queste demo, c'è un vantaggio strutturale nel separare il livello dati (DOM di cui verrebbe eseguito il rendering sulla pagina) dagli stili applicati. Gli stili sono scritti come possibili varianti che risiedono all'interno dello stile dei componenti, mentre un endpoint potrebbe inviare i dati che utilizzerebbe per definire lo stile del 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. La parte migliore è che puoi anche combinare questi valori. Se controlli sia --sunny sia --cloudy, lo stile potrebbe essere 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):

Applica uno stile alla scheda mediante 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. Le query dei container sono molto utili per 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 di stile per gli stili CSS al di là delle proprietà personalizzate. Fa già parte del livello di specifica corrente, ma non è ancora implementato in alcun browser. La valutazione del contesto booleano dovrebbe essere aggiunta al livello della specifica corrente quando il problema in sospeso viene risolto, mentre è pianificata l'esecuzione di query sull'intervallo per il livello successivo della specifica.