CSS nesting – verschachteln
Statt einen Selektor wiederholt mit verschiedenen Kind-Elementen oder Pseudo-Selektoren zu notieren, setzt das native CSS Nesting eine untergeordnete Regel in eine übergeordnete Regel.
header { background: ivory; & h1 { font-size: 2.2rem; color: green; } & p { font-size: 1.2rem; color: blue; } }
Dabei entsteht eine übersichtliche Hierarchie, die besser lesbar und einfacher zu ändern ist.
<header> <h1>Header</h1> <p>Ein Absatz im header-Element <a href="post.html">mit einem Link</a></p> </header>
Das CSS für dieses Beispiel ist schlicht und einfach, aber CSS-Regeln für komplexere Strukturen verteilen sich kreuz und quer über die gesamte CSS-Datei, je nachdem an welcher Stelle des Layouts und mit welcher Media Query die Struktur eingesetzt wird. Die Selektoren werden länger und länger.
CSS-Regeln verschachteln
Mit CSS Nesting ändert sich die Schreibweise wie folgt: Die Kind-Elemente werden unterhalb des Eltern-Elements eingetragen.
main header { background: silver; margin: auto; padding: 1rem; p { font-size: 1.2rem; background: ivory; padding: 1rem; a { text-decoration: none; } } }
Klassen- und id-Selektoren werden mit einem führenden & eingesetzt.
a { text-decoration: none; &:hover { color: darkorange; } }
Nesting macht das CSS modularer, spiegelt die inhaltlichen Zusammenhänge besser wieder und hält die Regeln der Strukturen zusammen.
Dabei unterscheidet sich das native CSS Nesting von dem der Präprozessoren wie Sass: Natives CSS wird vom Browser geparst und muss nicht übersetzt werden.
Nesting und @media-Regeln
@media-Queries können direkt in die CSS-Regeln eines Selektors gesetzt werden.
body { font-size: 1.1em; @media (max-width: 700px) { & { background: ivory; } } @media (max-device-width: 480px) { & { -webkit-text-size-adjust: 100% } } }
Das & vor dem Selektor
Wie schon die Regel a:hover gezeigt hat, brauchen einige Regeln und auch einige ältere Browser ein führendes & (Safari 16.5, Chrome und Edge 112-119). Da die jüngere Browsergeneration die &-Schreibweise auch weiterhin unterstützt, kann man einfach dabei bleiben.
Das führende & ist sozusagen die Referenz auf den übergeordneten Selektor und verbessert zudem die Lesbarkeit.
main header { background: #efefef; margin: auto; padding: 1rem; margin: 0.5rem; & p { font-size: 1.2rem; background: ivory; padding: 1rem; & a { // Leerzeichen: Unterordnung text-decoration: none; &:hover { // kein Leerzeichen: Klasse, Klassen- oder Pseudo-Selektor color: darkorange } } } }
Wichtig:Klassen-, id-, Attribut- und Pseudo-Selektoren haben kein Leerzeichen nach dem &. Oder anders herum: Nur bei Element-Selektoren sitzt ein trennendes Leerzeichen zwischen dem & und dem Selektor.
header h2 { color:tomato; } header h2.entry-title { color: green; }
Sitzt also Leerzeichen zwischen & und dem Selektor, liegt ein class-Selektor für dieses Element vor, mit einem Leerzeichen wird ein untergeordnetes Element referenziert. Das gilt auch für id-Selektoren, : und ::, für * und die Spielarten +, ~, > und für [] (Attribut-Selektoren).
Aus dem klassischen CSS oberhalb wird zu
header { & h2 { // mit Leerzeichen color: tomato; &.entry-title { // kein Leerzeichen color: green; } } }
Ersetzt man jetzt jedes & mit dem Selektor des übergeordneten Elements entsteht, wieder das ursprüngliche – nicht verschachtelte – CSS.
header h2 {color: tomato; } header h2.entry-title {color: green;}
Kompaktes CSS
Je kürzer die CSS-Regeln gehalten werden, desto lesbarer wird die CSS-Datei. Was in der linearen Schreibweise noch viele Zeilen einnimmt, läßt sich deutlich reduzieren.
#blog-layout h2, #blog-layout ul, #blog-layout div, #blog-layout p { padding: 0 1rem; max-width: 320px; margin: 0 auto; color: darkblue; }
Mein kleiner Blog
Hallo Absatz!
- Punkt 1
- Punkt 2
In einem ersten Schritt fasst der :is-Selektor die beteiligten Selektoren zusammen:
:is(#blog-layout) p, ul, h2, div { padding: 0 1rem; max-width: 320px; margin: 0 auto; color: darkblue; }
Auf dieselbe Weise übernimmt das Nesting die Regeln.
#blog-layout { & h2, & ul, & div, & p { padding: 0 1rem; max-width: 320px; margin: 0 auto; color: darkblue; } }
CSS Nesting und Spezifität
Die Spezifität ist ein Regelsatz, der bestimmt, welche Regeln auf ein Element angewendet werden, wenn zwei oder mehr Selektoren für dasselbe Element notiert sind. In der CSS-Kaskade hat unter normalen Umständen der letzte Selektor das höchste Gewicht.
<article id="excerpt"> <div> <h2 class="main-heading">Überschrift auf Ebene 2</h2> </div> </article> <article class="normal"> <div> <h3>Überschrift auf Ebene 3</h3> </div> </article>
Überschrift auf Ebene 2
Überschrift auf Ebene 3
Der Block ist mit den folgenden Stilen gestylt:
#excerpt, .normal { background: var(--me-dim-background); margin: 0.5rem; padding: 1rem; & h2, & h3 { color: tomato } }
Wenn die Klasse main-heading des h2-Elements an einer später folgenden Stelle verwendet wird, passiert … nichts (!).
.main-heading { color: blue; }
Die zusätzliche Regel an einer späteren Position überschreibt die Farbe für das h2-Element nicht. Die verschachtelten Regeln lassen sich ja auch mit einem :is()-Selektor schreiben:
:is(#excerpt, .normal) h1, h2 { color: tomato }
Ein :is()-Selektor übernimmt die Spezifität des Elements der höchsten Spezifität. Im vorangegangenen Beispiel ist das der id-Selektor #excerpt. Die Stile des id-Selektors haben eine sehr hohe Priorität, so das es schwer ist, diese Stile zu überschreiben.
Dieses Verhalten vermeidet, dass immer komplexere Selektoren oder !important benötigt werden, um Elemente von weiteren Stilen abzuschotten.
Kann CSS-Nesting heute schon genutzt werden?
Die volle Unterstützung bei dem Mainstream-Browsern hat Nesting zwar erst seit Ende 2024, aber schon Mitte 24 unterstützten die Browser Nesting, wenn Element-Selektoren mit einem führenden & geschrieben wurden.
Darüber hinaus kann Nesting-CSS genauso wie das CSS der Präprozessoren übersetzt werden.
Für die Übersetzung werden nur wenige Zeilen JavaScript gebraucht. Die Übersetzung fällt aber keineswegs komfortabel aus. Das installiert postcss und postcss-nesting:
npm install --save-dev postcss postcss-nested
Das Script wird auf der Kommandozeile aufgerufen oder eine kleine Node.js-Anwendung dafür geschrieben:
const postcss = require('postcss');
const nested = require('postcss-nested');
const nestedCSS = `
layout-header {
& .top-menu {
background: #444;
padding: 0.5rem;
margin-bottom: 1rem;
letter-spacing: 1px;
.reframe {
margin: 0 auto 0 auto;
display: flex;
justify-content: center;
gap: 18px;
}
}
}
`;
postcss([nested])
.process(nestedCSS, { from: undefined })
.then(result => {
console.log(result.css);
})
.catch(error => {
console.error(error);
});
Das Ergebnis:
layout-header .top-menu { background: #444; padding: 0.5rem; margin-bottom: 1rem; letter-spacing: 1px; } layout-header .top-menu .reframe { margin: 0 auto 0 auto; display: flex; justify-content: center; gap: 18px; }
supportsCSSNesting enthält die Abfrage,ob Nesting vom aktuellen Browser unterstützt wird. Wenn nicht, ersetzt das Skript kurzerhand die verschachtelte CSS-Datei mit der linearen Version.
function supportsCSSNesting() { try { document.querySelector("&"); return true; } catch (e) { const link = document.querySelector ("link[href='/css/nesting.css']"); link.href = "/style/style.css"; return false; } } supportsCSSNesting();