Tiefer in Abfragen im Containerstil eintauchen

Quellknoten: 1765194

Ich habe einiges aufgeschrieben erste Gedanken zu Abfragen im Containerstil eine Weile zurück. Es ist noch früh. Sie sind bereits in definiert CSS Containment Module Level 1-Spezifikation (derzeit im Status Editor's Draft), aber es finden noch einige ausstehende Diskussionen statt.

Die Grundidee ist, dass wir einen Container definieren und dann Stile bedingt auf seine Nachkommen anwenden können, basierend auf seinem berechneten Stil.

@container ?  {
  /* conditional styles */
}

Das beste Beispiel, das ich bisher gesehen habe, ist das Entfernen von Kursivschrift von so etwas wie , und wenn sie in einem Kontext verwendet werden, in dem der Inhalt bereits kursiv ist:

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;
  }
}

Das ist die allgemeine Idee. Aber falls Sie es noch nicht wussten, Miriam Suzanne, die Redakteurin der Spezifikation ist, führt eine fortlaufende und gründliche Reihe von persönliche Notizen zu Abfragen im Containerstil das ist öffentlich zugänglich. Es wurde neulich aktualisiert und ich habe einige Zeit damit verbracht, mich mit nuancierteren Aspekten von Stilabfragen zu befassen. Es ist inoffizielles Zeug, aber ich dachte, ich schreibe einige Dinge auf, die mir aufgefallen sind. Wer weiß? Vielleicht ist es etwas, auf das wir uns irgendwann freuen können!

Jedes Element ist ein Stilcontainer

Wir müssen a nicht einmal explizit zuweisen container-name or container-type um einen Style-Container zu definieren, da alles standardmäßig ein Style-Container ist.

Sie sehen also das obige Beispiel, das die Kursivschrift entfernt? Beachten Sie, dass es keinen Container identifiziert. Es springt mit dem direkt zur Abfrage style() Funktion. Welcher Container wird also abgefragt? Es wird die direkter Elternteil der Elemente Empfangen der angewendeten Stile. Und wenn nicht, dann ist es das der nächstnächste relative Container das hat Vorrang.

Ich mag es. Es ist sehr CSS-lastig, dass die Abfrage nach einer Übereinstimmung sucht und dann weiter nach oben sprudelt, bis sie eine übereinstimmende Bedingung findet.

Es war für mein kleines Gehirn schwer zu verstehen, warum wir mit einem impliziten Container auf der Grundlage von Stilen davonkommen, aber nicht so sehr, wenn wir uns mit dimensionalen Abfragen befassen, wie z size und inline-size. Miriam erklärt es schön:

Dimensionsabfragen erfordern CSS Containment von Größe, Layout und Stil des Containers ab, um Layoutschleifen zu vermeiden. Eindämmung ist eine invasive Sache, um sie breit anzuwenden, daher war es wichtig, dass die Autoren sorgfältig kontrollieren können, welche Elemente Containergrößen haben (oder nicht).

Stilbasierte Abfragen haben nicht dieselbe Einschränkung. In CSS gibt es bereits keine Möglichkeit, dass Nachkommenstile einen Einfluss auf die berechneten Stile eines Vorfahren haben. Daher ist keine Eindämmung erforderlich, und es gibt keine invasiven oder unerwarteten Nebenwirkungen bei der Etablierung eines Elements als a Abfragecontainer im Stil.

(Hervorhebung von mir)

Es läuft alles auf Konsequenzen hinaus – von denen es keine gibt, da alles ein sofort einsatzbereiter Container für Stilabfragen ist.

  • Wenn ein Container gefunden wird: Bedingungen werden für diesen Container aufgelöst.
  • Wenn mehrere Container übereinstimmen: Der nächste relative Container hat Vorrang.
  • Wenn keine Übereinstimmungen gefunden werden: unknown ist zurückgekommen.

Das ist dasselbe „verzeihender“ Geist wie der Rest von CSS.

Ein Container kann sowohl Dimensions- als auch Stilabfragen unterstützen

Angenommen, wir möchten eine Stilabfrage ohne explizit definieren container-name:

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

Das funktioniert weil Alle Elemente sind Stilbehälter, egal die container-type. Das ermöglicht es uns, Stile implizit abzufragen und uns auf die nächste Übereinstimmung zu verlassen. Und das ist völlig in Ordnung, da es wiederum keine nachteiligen Nebenwirkungen beim Erstellen von Stilcontainern gibt.

Wir müssen eine explizite verwenden container-type für dimensionale Abfragen, aber nicht so sehr für Stilabfragen, da jedes Element eine Stilabfrage ist. Das bedeutet auch, dass dieser Behälter sowohl ein Stil ist und Dimensionsabfrage:

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

Ausschließen eines Containers von der Abfrage

Vielleicht möchten wir nicht, dass ein Container am Abgleichsprozess teilnimmt. Da könnte man vielleicht ansetzen container-type: none auf einem Element.

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

Abfragecontainer im expliziten Stil bieten mehr Kontrolle darüber, was abgefragt wird

Wenn wir beispielsweise eine Stilabfrage für schreiben würden padding , gibt es keine zuverlässige Möglichkeit, den am besten passenden Container zu ermitteln, unabhängig davon, ob wir mit einem explizit benannten Container oder dem nächsten direkt übergeordneten Container arbeiten. Das ist, weil padding ist kein vererbtes Eigentum.

In diesen Fällen sollten wir also verwenden container-name um dem Browser explizit mitzuteilen, aus welchen Containern er ziehen kann. Wir können einem Container sogar mehrere explizite Namen geben, damit er mehr Bedingungen erfüllt:

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

Oh und container-name akzeptiert eine beliebige Anzahl von optionalen und wiederverwendbar Namen für einen Container! Das ist noch mehr Flexibilität, wenn es darum geht, dem Browser bei der Suche nach Übereinstimmungen zu helfen, eine Auswahl zu treffen.

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

Ich frage mich, ob dies auch als „Fallback“ angesehen werden kann, falls ein Container übergangen wird.

Stilabfragen können kombiniert werden

Das or und and Operatoren erlauben es uns, Wueries zu kombinieren, um die Dinge TROCKEN zu halten:

@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. */
}

Stile umschalten

Es gibt eine kleine Überschneidung zwischen Abfragen im Containerstil und Es wird daran gearbeitet, a zu definieren toggle() Funktion. Zum Beispiel können wir durch zwei radeln font-style Werte, sprich italic und normal:

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

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

Kühl. Aber der Vorschlag für CSS Toggles legt nahe, dass die toggle() Funktion wäre ein einfacherer Ansatz:

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

Aber alles, was über diese Art von binärem Anwendungsfall hinausgeht, ist wo toggle() ist weniger geeignet. Stilabfragen sind jedoch gut zu gehen. Miriam identifiziert drei Fälle, in denen Stilabfragen besser geeignet sind als 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;
  }
}

Stilabfragen lösen den „Custom Property Toggle Hack“

Beachten Sie, dass Stilabfragen eine formale Lösung für die sind „Trick zum Umschalten benutzerdefinierter CSS-Eigenschaften“. Dort setzen wir eine leere benutzerdefinierte Eigenschaft (--foo: ;) und verwenden Sie die durch Kommas getrennte Fallback-Methode, um Eigenschaften ein- und auszuschalten, wenn die benutzerdefinierte Eigenschaft auf einen realen Wert festgelegt ist.

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. */
}

Das ist super cool, auch eine Menge Arbeit, die Stil-Container-Abfragen trivial macht.

Stilabfragen und CSS-generierte Inhalte

Für generierte Inhalte, die von der content Eigentum von ::before und ::after Pseudo-Elemente, der passende Container ist das Element, auf dem der Inhalt generiert wird.

.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;
  }
}

Gestalten Sie Abfragen und Webkomponenten

Wir können eine Webkomponente als Container definieren und sie nach Stil abfragen. Erstens haben wir die des Bauteils:


  
… …

Dann verwenden wir die :host Pseudo-Element als Container zum Setzen von a container-name, eine container-type, und einige High-Level-Attribute darauf:

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

Elemente innerhalb der kann die Parameter der abfragen Element:

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

Was kommt als nächstes?

Auch hier basiert alles, was ich hier niedergeschrieben habe, auf Miriams Notizen, und diese Notizen sind kein Ersatz für die offizielle Spezifikation. Aber sie sind ein Hinweis darauf, was diskutiert wird und wo die Dinge in Zukunft landen könnten. Ich weiß es zu schätzen, dass Miriam eine Handvoll ausstehender Diskussionen verlinkt hat, die noch stattfinden und denen wir folgen können, um auf dem Laufenden zu bleiben:

Zeitstempel:

Mehr von CSS-Tricks