CSS-Verschachtelung

Eine unserer Lieblingsfunktionen von CSS-Präprozessoren ist jetzt in die Sprache integriert: das Verschachteln von Stilregeln.

Vor der Verschachtelung musste jeder Selektor explizit und separat deklariert werden. Das führte zu Wiederholungen, großen Stylesheets und einer unübersichtlichen Autorenumgebung.

Vorher
.nesting {
  color: hotpink;
}

.nesting > .is {
  color: rebeccapurple;
}

.nesting > .is > .awesome {
  color: deeppink;
}

Nach der Verschachtelung können Selektoren fortgesetzt und zugehörige Stilregeln darin gruppiert werden.

Nach
.nesting {
  color: hotpink;

  > .is {
    color: rebeccapurple;

    > .awesome {
      color: deeppink;
    }
  }
}

Im Browser testen.

Die Verschachtelung hilft Entwicklern, da sie die Notwendigkeit reduziert, Selektoren zu wiederholen, und gleichzeitig Stilregeln für verwandte Elemente zusammenfasst. Außerdem können Stile so besser mit dem HTML-Code übereinstimmen, auf den sie angewendet werden. Wenn die Komponente .nesting im vorherigen Beispiel aus dem Projekt entfernt wurde, können Sie die gesamte Gruppe löschen, anstatt in Dateien nach zugehörigen Selektorinstanzen zu suchen.

Die Verschachtelung kann in folgenden Bereichen helfen: - Organisation - Reduzierung der Dateigröße - Refactoring

Die Verschachtelung ist ab Chrome 112 und auch in der Safari Technical Preview 162 verfügbar.

Erste Schritte mit der CSS-Verschachtelung

Im restlichen Teil dieses Beitrags wird die folgende Demo-Sandbox verwendet,um die Auswahl zu visualisieren. In diesem Standardzustand ist nichts ausgewählt und alles ist sichtbar. Wenn Sie die verschiedenen Formen und Größen auswählen, können Sie die Syntax üben und in Aktion sehen.

Ein farbenfrohes Raster aus kleinen und großen Kreisen, Dreiecken und Quadraten.

In der Sandbox befinden sich Kreise, Dreiecke und Quadrate. Einige sind klein, mittel oder groß. Andere sind blau, rosa oder lila. Sie befinden sich alle im Containerelement .demo. Im Folgenden sehen Sie eine Vorschau der HTML-Elemente, auf die Sie abzielen.

<div class="demo">
  <div class="sm triangle pink"></div>
  <div class="sm triangle blue"></div>
  <div class="square blue"></div>
  <div class="sm square pink"></div>
  <div class="sm square blue"></div>
  <div class="circle pink"></div>
  …
</div>

Beispiele für die Verschachtelung

Mit der CSS-Verschachtelung können Sie Stile für ein Element im Kontext eines anderen Selektors definieren.

.parent {
  color: blue;

  .child {
    color: red;
  }
}

In diesem Beispiel ist der .child Klassenselektor in den .parent Klassenselektor verschachtelt. Das bedeutet, dass der verschachtelte Selektor .child nur auf Elemente angewendet wird, die untergeordnete Elemente von Elementen mit der Klasse .parent sind.

Dieses Beispiel kann alternativ mit dem Symbol & geschrieben werden, um explizit anzugeben, wo die übergeordnete Klasse platziert werden soll.

.parent {
  color: blue;

  & .child {
    color: red;
  }
}

Diese beiden Beispiele sind funktional gleichwertig. Der Grund für die verschiedenen Optionen wird deutlicher, wenn wir uns komplexere Beispiele ansehen.

Kreise auswählen

In diesem ersten Beispiel sollen nur die Kreise in der Demo ausgeblendet und unscharf gemacht werden.

Ohne Verschachtelung, CSS heute:

.demo .circle {
  opacity: .25;
  filter: blur(25px);
}

Mit Verschachtelung gibt es zwei gültige Möglichkeiten:

/* & is explicitly placed in front of .circle */
.demo {
  & .circle {
    opacity: .25;
    filter: blur(25px);
  }
}

oder

/* & + " " space is added for you */
.demo {
  .circle {
    opacity: .25;
    filter: blur(25px);
  }
}

Das Ergebnis: Alle Elemente in .demo mit der Klasse .circle sind unscharf und fast unsichtbar:

Das farbenfrohe Raster aus Formen hat keine Kreise mehr,
    sie sind nur noch sehr schwach im Hintergrund zu sehen.
Demo ausprobieren

Alle Dreiecke und Quadrate auswählen

Für diese Aufgabe müssen mehrere verschachtelte Elemente ausgewählt werden, auch Gruppenselektor genannt.

Ohne Verschachtelung, CSS heute, gibt es zwei Möglichkeiten:

.demo .triangle,
.demo .square {
  opacity: .25;
  filter: blur(25px);
}

oder mit :is():

/* grouped with :is() */
.demo :is(.triangle, .square) {
  opacity: .25;
  filter: blur(25px);
}

Mit Verschachtelung gibt es zwei gültige Möglichkeiten:

.demo {
  & .triangle,
  & .square {
    opacity: .25;
    filter: blur(25px);
  }
}

oder

.demo {
  .triangle, .square {
    opacity: .25;
    filter: blur(25px);
  }
}

Das Ergebnis: Nur .circle Elemente bleiben in .demo übrig:

Im bunten Raster mit Formen sind nur noch Kreise zu sehen, alle anderen Formen sind fast unsichtbar.
Demo ausprobieren

Große Dreiecke und Kreise auswählen

Für diese Aufgabe ist ein zusammengesetzter Selektor erforderlich, wobei Elemente beide Klassen haben müssen, um ausgewählt zu werden.

Ohne Verschachtelung, CSS heute:

.demo .lg.triangle,
.demo .lg.square {
  opacity: .25;
  filter: blur(25px);
}

oder

.demo .lg:is(.triangle, .circle) {
  opacity: .25;
  filter: blur(25px);
}

Mit Verschachtelung gibt es zwei gültige Möglichkeiten:

.demo {
  .lg.triangle,
  .lg.circle {
    opacity: .25;
    filter: blur(25px);
  }
}

oder

.demo {
  .lg {
    &.triangle,
    &.circle {
      opacity: .25;
      filter: blur(25px);
    }
  }
}

Das Ergebnis: Alle großen Dreiecke und Kreise sind in .demo ausgeblendet:

Im farbenfrohen Raster sind nur kleine und mittelgroße Formen zu sehen.
Demo ausprobieren
Profi-Tipp für zusammengesetzte Selektoren und Verschachtelung

Das Symbol & ist hier hilfreich, da es explizit zeigt, wie verschachtelte Selektoren verknüpft werden. Dazu ein Beispiel:

.demo {
  .lg {
    .triangle,
    .circle {
      opacity: .25;
      filter: blur(25px);
    }
  }
}

Das ist zwar eine gültige Möglichkeit zur Verschachtelung, die Ergebnisse stimmen aber nicht mit den erwarteten Elementen überein. Der Grund dafür ist, dass ohne & zur Angabe des gewünschten Ergebnisses von .lg.triangle, .lg.circle zusammengesetzt, das tatsächliche Ergebnis .lg .triangle, .lg .circle wäre, also Nachkommensselektoren.

Alle Formen außer den rosafarbenen auswählen

Für diese Aufgabe ist eine funktionale Pseudoklasse für die Negation erforderlich, bei der Elemente den angegebenen Selektor nicht haben dürfen.

Ohne Verschachtelung, CSS heute:

.demo :not(.pink) {
  opacity: .25;
  filter: blur(25px);
}

Mit Verschachtelung gibt es zwei gültige Möglichkeiten:

.demo {
  :not(.pink) {
    opacity: .25;
    filter: blur(25px);
  }
}

oder

.demo {
  & :not(.pink) {
    opacity: .25;
    filter: blur(25px);
  }
}

Das Ergebnis: Alle Formen, die nicht rosa sind, sind in .demo ausgeblendet:

Das farbenfrohe Raster ist jetzt einfarbig und zeigt nur noch rosafarbene Formen.
Demo ausprobieren
Präzision und Flexibilität mit &

Angenommen, Sie möchten .demo mit dem Selektor :not() auswählen. Dazu ist & erforderlich:

.demo {
  &:not() {
    ...
  }
}

Dadurch werden .demo und :not() zu .demo:not() zusammengesetzt, im Gegensatz zum vorherigen Beispiel, bei dem .demo :not() erforderlich war. Diese Erinnerung ist sehr wichtig, wenn Sie eine :hover-Interaktion verschachteln möchten.

.demo {
  &:hover {
    /* .demo:hover */
  }

  :hover {
    /* .demo :hover */
  }
}

Weitere Beispiele für die Verschachtelung

Die CSS-Spezifikation für die Verschachtelung enthält weitere Beispiele. Wenn Sie mehr über die Syntax anhand von Beispielen erfahren möchten, finden Sie dort eine breite Palette gültiger und ungültiger Beispiele.

In den nächsten Beispielen wird kurz eine Funktion für die CSS-Verschachtelung vorgestellt, damit Sie die Bandbreite der Möglichkeiten besser verstehen.

@media verschachteln

Es kann sehr ablenkend sein, zu einem anderen Bereich des Stylesheets zu wechseln, um Media-Query-Bedingungen zu finden, die einen Selektor und seine Stile ändern. Diese Ablenkung entfällt, da Sie die Bedingungen direkt im Kontext verschachteln können.

Aus Gründen der Syntax kann eine minimale Syntax verwendet werden, wenn die verschachtelte Media-Query nur die Stile für den aktuellen Selektorkontext ändert.

.card {
  font-size: 1rem;

  @media (width >= 1024px) {
    font-size: 1.25rem;
  }
}

Sie können auch explizit & verwenden:

.card {
  font-size: 1rem;

  @media (width >= 1024px) {
    &.large {
      font-size: 1.25rem;
    }
  }
}

In diesem Beispiel wird die erweiterte Syntax mit & verwendet und gleichzeitig auf .large-Karten ausgerichtet, um zu zeigen, dass zusätzliche Verschachtelungsfunktionen weiterhin funktionieren.

Weitere Informationen zum Verschachteln von @-Regeln

Verschachtelung überall

In allen bisherigen Beispielen wurde ein vorheriger Kontext fortgesetzt oder erweitert. Sie können den Kontext bei Bedarf vollständig ändern oder neu anordnen.

.card {
  .featured & {
    /* .featured .card */
  }
}

Das Symbol & steht für einen Verweis auf ein Selektorobjekt (keine String) und kann an einer beliebigen Stelle in einem verschachtelten Selektor platziert werden. Es kann sogar mehrmals platziert werden:

.card {
  .featured & & & {
    /* .featured .card .card .card */
  }
}

Dieses Beispiel sieht zwar etwas nutzlos aus, aber es gibt sicherlich Szenarien, in denen es praktisch ist, einen Selektorkontext zu wiederholen.

Ungültige Beispiele für die Verschachtelung

Es gibt einige Szenarien für die Syntax der Verschachtelung, die ungültig sind und Sie möglicherweise überraschen, wenn Sie bereits in Präprozessoren verschachtelt haben.

Verschachtelung und Verkettung

Viele CSS-Klassennamenkonventionen gehen davon aus, dass Selektoren durch Verschachtelung verkettet oder angehängt werden können, als wären sie Strings. Das funktioniert bei der CSS-Verschachtelung nicht, da die Selektoren keine Strings, sondern Objektverweise sind.

.card {
  &--header {
    /* is not equal to ".card--header" */
  }
}

Eine ausführlichere Erklärung finden Sie in der Spezifikation.

Kompliziertes Beispiel für die Verschachtelung

Verschachtelung in Selektorlisten und :is()

Sehen Sie sich den folgenden CSS-Block für die Verschachtelung an:

.one, #two {
  .three {
    /* some styles */
  }
}

Dies ist das erste Beispiel, das mit einer Selektorliste beginnt und dann weiter verschachtelt wird. In den vorherigen Beispielen wurde nur mit einer Selektorliste geendet. Dieses Beispiel für die Verschachtelung ist nicht ungültig, es gibt aber ein potenziell kompliziertes Implementierungsdetail zur Verschachtelung in Selektorlisten, insbesondere in solchen, die einen ID-Selektor enthalten.

Damit die Verschachtelung wie beabsichtigt funktioniert, wird jede Selektorliste, die nicht die innerste Verschachtelung ist, vom Browser mit :is() umschlossen. Durch diese Umschließung bleibt die Gruppierung der Selektorliste in allen erstellten Kontexten erhalten. Der Nebeneffekt dieser Gruppierung, :is(.one, #two), ist, dass sie die Spezifität des höchsten Werts innerhalb der Selektoren in den Klammern übernimmt. Das ist die normale Funktionsweise von :is(), kann aber überraschend sein, wenn Sie die Syntax für die Verschachtelung verwenden, da sie nicht genau dem entspricht, was Sie geschrieben haben. Zusammenfassend lässt sich sagen, dass die Verschachtelung mit IDs und Selektorlisten zu Selektoren mit sehr hoher Spezifität führen kann.

Um das komplizierte Beispiel noch einmal zusammenzufassen: Der vorherige Verschachtelungsblock wird so auf das Dokument angewendet:

:is(.one, #two) .three {
  /* some styles */
}

Achten Sie darauf oder weisen Sie Ihre Linter an, eine Warnung auszugeben, wenn Sie in einer Selektorliste verschachteln, die einen ID-Selektor verwendet. Die Spezifität aller Verschachtelungen in dieser Selektorliste ist dann hoch.

Verschachtelung und Deklarationen mischen

Sehen Sie sich den folgenden CSS-Block für die Verschachtelung an:

.card {
  color: green;
  & { color: blue; }
  color: red;
}

Die Farbe der .card-Elemente ist blue.

Alle gemischten Stildeklarationen werden nach oben verschoben, als wären sie vor der Verschachtelung geschrieben worden. Weitere Informationen finden Sie in der Spezifikation.

Es gibt Möglichkeiten, das zu umgehen. Im Folgenden werden die drei Farbstile in & umschlossen, wodurch die Kaskadenreihenfolge beibehalten wird, wie vom Autor beabsichtigt. Die Farbe der .card-Elemente ist rot.

.card {
  color: green;
  & { color: blue; }
  & { color: red; }
}

Es ist sogar eine gute Idee, alle Stile, die nach der Verschachtelung folgen, mit & zu umschließen.

.card {
  color: green;

  @media (prefers-color-scheme: dark) {
    color: lightgreen;
  }

  & {
    aspect-ratio: 4/3;
  }
}

Funktionserkennung

Es gibt zwei gute Möglichkeiten, die CSS-Verschachtelung zu erkennen: Verwenden Sie die Verschachtelung selbst oder verwenden Sie @supports, um die Parsing-Funktion für verschachtelte Selektoren zu prüfen.

Ein Screenshot der Codepen-Demo von Bramus, in der gefragt wird, ob Ihr Browser CSS-Nesting unterstützt. Unter dieser Frage befindet sich ein grünes Feld, das Unterstützung signalisiert.

Verschachtelung verwenden:

html {
  .has-nesting {
    display: block;
  }

  .no-nesting {
    display: none;
  }
}

@supports verwenden:

@supports (selector(&)) {
  /* nesting parsing available */
}

Mein Kollege Bramus hat ein tolles Codepen-Beispiel für diese Strategie.

Fehlerbehebung mit den Chrome-Entwicklertools

Die aktuelle Unterstützung für die Verschachtelung in den Entwicklertools ist minimal. Derzeit werden Stile wie erwartet im Bereich „Stile“ dargestellt, aber das Nachverfolgen der Verschachtelung und des vollständigen Selektorkontexts wird noch nicht unterstützt. Wir haben bereits ein Design und Pläne, um das zu ändern.

Screenshot der Chrome-Entwicklertools mit der Syntax für das Verschachteln.

In Chrome 113 soll die Unterstützung für die CSS-Verschachtelung erweitert werden. Bleiben Sie dran!

Die Zukunft

Die CSS-Verschachtelung ist erst in Version 1 verfügbar. Version 2 wird mehr syntaktischen Zucker und möglicherweise weniger Regeln zum Merken enthalten. Es gibt eine große Nachfrage danach, dass das Parsing der Verschachtelung nicht eingeschränkt ist oder zu Problemen führt.

Die Verschachtelung ist eine große Verbesserung für die CSS-Sprache. Sie hat Auswirkungen auf fast alle architektonischen Aspekte von CSS. Diese großen Auswirkungen müssen gründlich untersucht und verstanden werden, bevor Version 2 effektiv spezifiziert werden kann.

Zum Schluss noch eine Demo, in der hier ist eine Demo die @scope, Verschachtelung und @layer zusammen verwendet werden. Das ist wirklich spannend!

Eine helle Karte auf einem grauen Hintergrund. Die Karte hat einen Titel und Text,
  einige Aktionsschaltflächen und ein Bild im Cyberpunk-Stil.