Scavare più a fondo nelle query in stile contenitore

Nodo di origine: 1765194

Ne ho scritti alcuni primi pensieri sulle query in stile contenitore un po' di tempo fa. È ancora presto. Sono già definiti nel Specifica di livello 1 del modulo di contenimento CSS (attualmente nello stato di bozza dell'editore) ma ci sono ancora un paio di discussioni in sospeso in corso.

L'idea di base è che possiamo definire un contenitore e quindi applicare gli stili in modo condizionale ai suoi discendenti in base al suo stile calcolato.

@container ?  {
  /* conditional styles */
}

Il miglior esempio che ho visto finora è la rimozione del corsivo da qualcosa di simile , e quando vengono utilizzati in un contesto in cui il contenuto è già in corsivo:

em, i, q {
  font-style: italic; /* default UA behavior */
}

/* When the container's font-style is italic, remove italics from these elements. */
@container style(font-style: italic) {
  em, i, q {
    font-style: normal;
  }
}

Questa è l'idea generale. Ma se non lo sapevi, Miriam Suzanne, che è un redattore delle specifiche, mantiene una serie continua e completa di note personali sulle query in stile contenitore che è pubblicamente disponibile. È stato aggiornato l'altro giorno e ho trascorso un po' di tempo lì cercando di capire aspetti più sfumati delle query di stile. È roba non ufficiale, ma ho pensato di annotare alcune cose che mi hanno colpito. Chi lo sa? Forse è roba che alla fine possiamo aspettarci!

Ogni elemento è un contenitore di stile

Non abbiamo nemmeno bisogno di assegnare esplicitamente a container-name or container-type per definire un contenitore di stile perché tutto è un contenitore di stile per impostazione predefinita.

Quindi, vedi quell'esempio sopra che rimuove il corsivo? Si noti che non identifica un contenitore. Salta direttamente alla query utilizzando il style() funzione. Quindi, quale contenitore viene interrogato? Sarà il padre diretto degli elementi ricevere gli stili applicati. E se non quello, allora lo è il successivo contenitore relativo più vicino che ha la precedenza.

Mi piace. È molto CSS-y per la query cercare una corrispondenza, quindi continuare a gonfiarsi finché non trova una condizione corrispondente.

È stato difficile per il mio piccolo cervello capire perché possiamo farla franca con un contenitore implicito basato sugli stili, ma non così tanto quando abbiamo a che fare con query dimensionali, come size ed inline-size. Miriam lo spiega bene:

Le query dimensionali richiedono css contenimento sulla dimensione, il layout e lo stile del contenitore per evitare cicli di layout. Il contenimento è una cosa invasiva da applicare in generale, quindi era importante che gli autori avessero un controllo attento su quali elementi sono (o non sono) contenitori di dimensioni.

Le query basate sullo stile non hanno la stessa limitazione. Non c'è già modo nei CSS per gli stili discendenti di avere un impatto sugli stili calcolati di un antenato. Quindi non è richiesto alcun contenimento e non ci sono effetti collaterali invasivi o imprevisti nello stabilire un elemento come a contenitore di query di stile.

(enfasi mia)

Tutto si riduce alle conseguenze, di cui non ce ne sono per quanto riguarda tutto ciò che è un contenitore di query di stile appena estratto dagli schemi.

  • Se viene trovato un contenitore: le condizioni vengono risolte rispetto a quel contenitore.
  • Se più contenitori corrispondono: il contenitore relativo più vicino ha la precedenza.
  • Se non vengono trovate corrispondenze: unknown restituito.

È lo stesso spirito "perdonante" come il resto dei CSS.

Un contenitore può supportare sia query dimensionali che di stile

Diciamo che vogliamo definire una query di stile senza un esplicito container-name:

@container style(font-style: italic) {
  em {
    font-style: normal;
  }
}

Funziona perché tutti gli elementi sono contenitori di stile, non importa il container-type. Questo è ciò che ci consente di interrogare implicitamente gli stili e fare affidamento sulla corrispondenza più vicina. E questo va benissimo poiché, ancora una volta, non ci sono effetti collaterali negativi quando si stabiliscono contenitori di stile.

Dobbiamo usare un esplicito container-type per le query dimensionali, ma non tanto per le query di stile poiché ogni elemento è una query di stile. Ciò significa anche che questo contenitore è sia uno stile ed interrogazione dimensionale:

.card-container {
  container: card / inline-size; /* implictly a style query container as well */
}

Esclusione di un contenitore dall'interrogazione

Forse non vogliamo che un contenitore partecipi al processo di abbinamento. Ecco dove potrebbe essere possibile impostare container-type: none su un elemento.

.some-element {
  container-type: none;
}

I contenitori di query in stile esplicito offrono un maggiore controllo su ciò che viene interrogato

Se, diciamo, dovessimo scrivere una query di stile per padding , non esiste un modo affidabile per determinare il contenitore con la corrispondenza migliore, indipendentemente dal fatto che si stia lavorando con un contenitore denominato in modo esplicito o con l'elemento padre diretto più vicino. È perché padding non è una proprietà ereditaria.

Quindi, in quei casi, dovremmo usare container-name per informare esplicitamente il browser da quali contenitori possono estrarre. Possiamo persino assegnare a un contenitore più nomi espliciti per farlo corrispondere a più condizioni:

.card {
  container-name: card layout theme;
}

Oh, e container-name accetta qualsiasi numero di opzioni e riutilizzabile nomi per un contenitore! Questa è ancora più flessibilità quando si tratta di aiutare il browser a fare una scelta durante la ricerca di corrispondenze.

.theme {
  container-name: theme;
}
.grid {
  container-name: layout;
}
.card {
  container-name: card layout theme;
}

Mi chiedo se anche questo possa essere considerato un "ripiego" nel caso in cui un contenitore venga passato.

Le query di stile possono essere combinate

I or ed and gli operatori ci permettono di combinare wueries per mantenere le cose ASCIUTTE:

@container bubble style(--arrow-position: start start) or style(--arrow-position: end start) {
  .bubble::after {
    border-block-end-color: inherit;
    inset-block-end: 100%;
  }
}

/* is the same as... */
@container bubble style(--arrow-position: start start) {
  /* etc. */
}
@container bubble style(--arrow-position: end start) {
  /* etc. */
}

Stili alternati

C'è una piccola sovrapposizione tra le query in stile contenitore e lavoro in corso per definire a toggle() function. Ad esempio, possiamo scorrerne due font-style valori, diciamo italic ed normal:

em, i, q {
  font-style: italic;
}

@container style(font-style: italic) {
  em, i, q {
    font-style: normal;
  }
}

Freddo. Ma la proposta per CSS Toggles suggerisce che il file toggle() funzione sarebbe un approccio più semplice:

em, i, q {
  font-style: toggle(italic, normal);
}

Ma qualsiasi cosa al di là di questo tipo di caso d'uso binario è dove toggle() è meno adatto. Le query di stile, tuttavia, sono a posto. Miriam identifica tre casi in cui le query di stile sono più adatte di a toggle():

/* When font-style is italic, apply background color. */
/* Toggles can only handle one property at a time. */
@container style(font-style: italic) {
  em, i, q {
    background: lightpink;
  }
}

/* When font-style is italic and --color-mode equals light */
/* Toggles can only evaluate one condition at a time */
@container style((font-style: italic) and (--color-mode: light)) {
  em, i, q {
    background: lightpink;
  }
}

/* Apply the same query condition to multiple properties */
/* Toggles have to set each one individually as separate toggles */
@container style(font-style: italic) {
  em, i, q {
    /* clipped gradient text */
    background: var(--feature-gradient);
    background-clip: text;
    box-decoration-break: clone;
    color: transparent;
    text-shadow: none;
  }
}

Le query di stile risolvono il "Custom Property Toggle Hack"

Si noti che le query di stile sono una soluzione formale per il "Trucco per attivare/disattivare proprietà personalizzate CSS". Lì, impostiamo una proprietà personalizzata vuota (--foo: ;) e utilizza il metodo di fallback separato da virgole per "attivare e disattivare" le proprietà quando la proprietà personalizzata è impostata su un valore reale.

button {
  --is-raised: ; /* off by default */
  
  border: 1px solid var(--is-raised, rgb(0 0 0 / 0.1));
  box-shadow: var(
    --is-raised,
    0 1px hsl(0 0% 100% / 0.8) inset,
    0 0.1em 0.1em -0.1em rgb(0 0 0 / 0.2)
  );
  text-shadow: var(--is-raised, 0 -1px 1px rgb(0 0 0 / 0.3));
}

button:active {
  box-shadow: var(--is-raised, 0 1px 0.2em black inset);
}

#foo {
  --is-raised: initial; /* turned on, all fallbacks take effect. */
}

È fantastico, anche un sacco di lavoro che le query sui contenitori di stile rendono banali.

Query di stile e contenuto generato da CSS

Per i contenuti generati prodotti dal content proprietà di ::before ed ::after pseudo-elementi, il contenitore corrispondente è l'elemento su cui viene generato il contenuto.

.bubble {
  --arrow-position: end end;
  container: bubble;
  border: medium solid green;
  position: relative;
}

.bubble::after {
  content: "";
  border: 1em solid transparent;
  position: absolute;
}

@container bubble style(--arrow-position: end end) {
  .bubble::after {
    border-block-start-color: inherit;
    inset-block-start: 100%;
    inset-inline-end: 1em;
  }
}

Query di stile e componenti web

Possiamo definire un componente web come un contenitore ed interrogarlo in base allo stile. Innanzitutto, abbiamo il del componente:


  
… …

Quindi usiamo il :host pseudo-elemento come contenitore per impostare a container-name, un container-typee alcuni attributi di alto livello su di esso:

:host {
  container: media-host / inline-size;
  --media-location: before;
  --media-style: square;
  --theme: light;
}

Elementi all'interno del può interrogare i parametri del elemento:

@container media-host style(--media-style: round) {
  [part='img'] {
    border-radius: 100%;
  }
}

Qual è il prossimo passo?

Ancora una volta, tutte le cose che ho annotato qui si basano sugli appunti di Miriam, e quegli appunti non sostituiscono le specifiche ufficiali. Ma sono un'indicazione di cosa si sta discutendo e dove le cose potrebbero atterrare in futuro. Apprezzo che Miriam abbia collegato una manciata di discussioni in sospeso ancora in corso che possiamo seguire per rimanere aggiornati:

Timestamp:

Di più da Trucchi CSS