Erste Schritte mit Stilabfragen

Seit Kurzem werden in allen modernen Browser-Engines die Inline-Größe und die Werte für Container-Abfrageeinheiten abgefragt.

Unterstützte Browser

  • 105
  • 105
  • 110
  • 16

Quelle

Die Begrenzungsspezifikation umfasst mehr als nur Größenabfragen. Sie ermöglicht auch die Abfrage der Stilwerte eines übergeordneten Elements. Ab Chromium 111 können Sie Stilbegrenzungen auf Werte von benutzerdefinierten Eigenschaften anwenden und ein übergeordnetes Element nach dem Wert einer benutzerdefinierten Eigenschaft abfragen.

Unterstützte Browser

  • 111
  • 111
  • x
  • x

Quelle

Das bedeutet, dass wir im CSS-Code eine noch bessere logische Kontrolle der Stile haben und eine bessere Trennung der Anwendungslogik und der Datenschicht von ihren Stilen ermöglichen.

Die Spezifikation des CSS-Begrenzungsmoduls der Ebene 3, die Größen- und Stilabfragen abdeckt, ermöglicht die Abfrage aller Stile von einem übergeordneten Element, einschließlich Property- und Wertpaare wie font-weight: 800. Im Rahmen der Einführung dieser Funktion funktionieren Stilabfragen derzeit jedoch nur mit benutzerdefinierten CSS-Eigenschaftswerten. Dies ist immer noch sehr nützlich, um Stile zu kombinieren und Daten vom Design zu trennen. Sehen wir uns an, wie Sie Stilabfragen mit benutzerdefinierten CSS-Eigenschaften verwenden:

Erste Schritte mit Stilabfragen

Angenommen, wir haben folgenden HTML-Code:

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

Wenn Sie Stilabfragen verwenden möchten, müssen Sie zuerst ein Containerelement einrichten. Je nachdem, ob Sie ein direktes oder indirektes übergeordnetes Element abfragen, ist dafür ein etwas anderer Ansatz erforderlich.

Direkte übergeordnete Elemente abfragen

Diagramm einer Stilabfrage.

Anders als bei Stilabfragen müssen Sie keine Begrenzungen mithilfe der Eigenschaft container-type oder container auf .card-container anwenden, damit .card die Stile seines direkt übergeordneten Elements abfragen kann. Allerdings müssen die Stile (in diesem Fall die Werte benutzerdefinierter Eigenschaften) auf einen Container (in diesem Fall .card-container) oder auf ein beliebiges Element angewendet werden, das das Element enthält, das wir im DOM mit Stilen versehen. Wir können keine Stile anwenden, die wir auf das direkte Element abfragen, das wir mit dieser Abfrage gestalten, da dies zu Endlosschleifen führen könnte.

Um ein übergeordnetes Element direkt abzufragen, können Sie Folgendes schreiben:

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

Sie haben vielleicht bemerkt, dass die Stilabfrage die Abfrage in style() einschließt. Damit lassen sich Größenwerte von Stilen unterscheiden. Sie können beispielsweise eine Abfrage für die Breite des Containers als @container (min-width: 200px) { … } schreiben. Dadurch werden Designs angewendet, wenn der übergeordnete Container mindestens 200 Pixel breit ist. min-width kann jedoch auch eine CSS-Eigenschaft sein und Sie könnten den CSS-Wert von min-width mithilfe von Stilabfragen abfragen. Deshalb verwenden Sie den Wrapper style(), um den Unterschied zu verdeutlichen: @container style(min-width: 200px) { … }.

Stile für indirekte Eltern festlegen

Wenn Sie Stile für ein Element abfragen möchten, das kein direkt übergeordnetes Element ist, müssen Sie diesem Element einen container-name zuweisen. Beispielsweise können wir Stile basierend auf den Stilen von .card-list auf .card anwenden, indem wir .card-list einen container-name zuweisen und in der Stilabfrage darauf verweisen.

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

Im Allgemeinen hat es sich bewährt, den Containern Namen zu geben, um zu verdeutlichen, was Sie abfragen. So können Sie leichter auf diese Container zugreifen. Dies ist beispielsweise praktisch, wenn Sie Elemente direkt in .card gestalten möchten. Ohne einen benannten Container in .card-container können sie diesen nicht direkt abfragen.

Aber all dies ist in der Praxis viel sinnvoller. Sehen wir uns einige Beispiele an:

Abfragen mit Stil in Aktion

Demobild mit mehreren Produktkarten, teilweise mit der Kennzeichnung „neu“ oder „niedriger Lager“ und der Karte „niedriger Lagerbestand“ mit einem roten Hintergrund.

Stilabfragen sind besonders nützlich, wenn Sie entweder eine wiederverwendbare Komponente mit mehreren Varianten haben oder wenn Sie nicht die Kontrolle über alle Stile haben, aber in bestimmten Fällen Änderungen anwenden müssen. Dieses Beispiel zeigt eine Reihe von Produktkarten mit derselben Kartenkomponente. Einige Produktkarten enthalten zusätzliche Details/Hinweise wie „Neu“ oder „Niedriger Lagerbestand“, die durch eine benutzerdefinierte Eigenschaft mit dem Namen „--detail“ ausgelöst werden. Wenn ein Produkt den Status „Nur auf Lager“ hat, erhält es einen dunkelroten Rahmen. Diese Art von Informationen wird wahrscheinlich vom Server gerendert und kann über Inline-Stile wie folgt auf die Karten angewendet werden:

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

Aufgrund dieser strukturierten Daten können Sie Werte an --detail übergeben und diese benutzerdefinierte CSS-Eigenschaft verwenden, um die Stile anzuwenden:

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

Mit dem obigen Code können wir einen Chip für --detail: low-stock und --detail: new anwenden. Möglicherweise haben Sie aber eine Redundanz im Codeblock festgestellt. Derzeit ist es nicht möglich, nur das Vorhandensein von --detail mit @container style(--detail) abzufragen, um eine bessere Freigabe von Stilen und weniger Wiederholungen zu ermöglichen. Diese Funktion wird derzeit in der Arbeitsgruppe diskutiert.

Wetterkarten

Im vorherigen Beispiel wurde eine einzelne benutzerdefinierte Eigenschaft mit mehreren möglichen Werten zum Anwenden von Stilen verwendet. Sie können es jedoch auch durch die Verwendung von und Abfragen für mehrere benutzerdefinierte Eigenschaften mischen. Hier ein Beispiel für eine Wetterkarte:

Demo für Wetterkarten

Um die Farbabstufungen des Hintergrunds und die Symbole für diese Karten zu gestalten, suchen Sie nach Wettermerkmalen wie „bewölkt“, „regnerisch“ oder „sonnig“:

@container style(--sunny: true) {
  .weather-card {
    background: linear-gradient(-30deg, yellow, orange);
  }
  
  .weather-card:after {
    content: url(<data-uri-for-demo-brevity>);
    background: gold;
  }
}

So können Sie jede Karte basierend auf ihren individuellen Merkmalen gestalten. Sie können aber auch Kombinationen von charakteristischen (benutzerdefinierten Eigenschaften) gestalten, indem Sie den Kombinator and genau wie für Medienabfragen verwenden. Ein Tag, der sowohl bewölkt als auch sonnig ist, würde beispielsweise so aussehen:

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

Daten vom Design trennen

In beiden Demos ergibt sich ein struktureller Vorteil, dass die Datenschicht (DOM, das auf der Seite gerendert wird) von den angewendeten Stilen getrennt wird. Die Stile werden als mögliche Varianten innerhalb des Komponentenstils geschrieben, während ein Endpunkt die Daten senden könnte, die er dann zum Gestalten der Komponente verwenden würde. Sie können einen einzelnen Wert verwenden, z. B. im ersten Fall, den Wert --detail aktualisieren, oder mehrere Variablen, wie im zweiten Fall. Legen Sie entweder --rainy, --cloudy oder --sunny fest. Und das Beste daran ist, dass Sie diese Werte auch kombinieren können. Wenn Sie nach --sunny und --cloudy suchen, könnte ein teilweise bewölkter Stil angezeigt werden.

Die Werte benutzerdefinierter Eigenschaften können über JavaScript nahtlos aktualisiert werden, entweder beim Einrichten des DOM-Modells (d.h. beim Erstellen der Komponente in einem Framework) oder jederzeit mit <parentElem>.style.setProperty('--myProperty’, <value>) aktualisiert werden. I

In dieser Demo sehen Sie in einigen Codezeilen den --theme einer Schaltfläche und wendet Stile mithilfe von Stilabfragen und dieser benutzerdefinierten Eigenschaft (--theme) an:

Gestalten Sie die Karte mithilfe von Stilabfragen. Das JavaScript, das zum Aktualisieren der Werte der benutzerdefinierten Eigenschaften verwendet wird, ist:

const themePicker = document.querySelector('#theme-picker')
const btnParent = document.querySelector('.btn-section');

themePicker.addEventListener('input', (e) => {
  btnParent.style.setProperty('--theme', e.target.value);
})

Die in diesem Artikel beschriebenen Funktionen sind nur der Anfang. Von Containerabfragen können Sie mehr erwarten, um dynamische, responsive Oberflächen zu erstellen. Insbesondere bei Stilabfragen gibt es noch einige offene Probleme. Eine davon ist die Implementierung von Stilabfragen für CSS-Stile über benutzerdefinierte Eigenschaften hinaus. Dies ist bereits in der aktuellen Spezifikationsebene enthalten, wurde aber noch in keinem Browser implementiert. Die Auswertung des booleschen Kontexts wird voraussichtlich der aktuellen Spezifikationsebene hinzugefügt, wenn das ausstehende Problem behoben wird, während Bereichsabfragen für die nächste Ebene der Spezifikation geplant sind.