Verschachteltes CSS – ganz ohne Sass, direkt im Browser
Das Feature, für das die meisten Leute überhaupt erst einen CSS-Präprozessor eingerichtet haben, kann der Browser inzwischen selbst. Kein Build-Schritt, keine Abhängigkeit – nur ein paar Regeln, die man kennen sollte.
Ich habe jahrelang Sass eingerichtet, hauptsächlich wegen einer einzigen Sache: Verschachtelung. Zusammengehörige Regeln standen dadurch zusammen statt über die Datei verteilt. Dafür brauchte es einen Build-Schritt, eine Abhängigkeit und einen Ordner mit generierten Dateien.
Das ist inzwischen erledigt — der Browser kann es selbst:
.karte {
padding: 16px;
border: 1px solid var(--line);
border-radius: 12px;
& h3 {
margin: 0 0 6px;
font-size: 17px;
}
& p {
color: var(--muted);
line-height: 1.5;
}
&:hover {
border-color: var(--akzent);
}
@media (max-width: 600px) {
padding: 12px;
}
}Alles, was .karte betrifft, steht an einer Stelle — inklusive Hover-Zustand und Media Query. Kein Suchen mehr nach der zugehörigen @media-Regel dreihundert Zeilen weiter unten.
Das kaufmännische Und
& steht für den äußeren Selektor. Der Unterschied ist wichtig:
.karte {
& .titel { } /* .karte .titel – ein Nachfahre */
&.aktiv { } /* .karte.aktiv – dasselbe Element */
& + & { } /* .karte + .karte – die nächste Karte */
}In den meisten Fällen darf man & vor einem Nachfahren-Selektor weglassen — h3 { … } funktioniert genauso wie & h3 { … }. Ich schreibe es trotzdem hin. Es kostet zwei Zeichen und macht beim Überfliegen sofort klar, dass hier verschachtelt wird.
Bei &:hover und &.aktiv ist es dagegen zwingend, weil sich sonst die Bedeutung ändert.
Die eine Regel, die man wirklich beachten muss
Nicht zu tief verschachteln. Das war schon bei Sass der klassische Fehler und ist hier derselbe:
/* ⚠️ so nicht */
.seite {
& .inhalt {
& .karte {
& .titel {
& a { color: red; } /* .seite .inhalt .karte .titel a */
}
}
}
}Das Ergebnis ist ein Selektor mit einer Spezifität, gegen die man später nur noch mit !important ankommt. Meine Grenze: zwei Ebenen. Wird es tiefer, ist das ein Hinweis, dass der Baustein eine eigene Klasse verdient hätte.
Was ich damit gewonnen habe
Der eigentliche Gewinn ist nicht die Verschachtelung, sondern das, was ich dafür nicht mehr brauche: keinen Build-Schritt, keine Node-Abhängigkeit, keine generierten Dateien im Repository. Die CSS-Datei, die im Browser landet, ist genau die, die ich geschrieben habe — mit Zeilennummern, die in den Entwicklerwerkzeugen stimmen.
Für ein kleines Projekt war eine Sass-Einrichtung schon immer schwer zu rechtfertigen. Jetzt gibt es dafür fast keinen Grund mehr. Wer Variablen braucht, hat mit var(--…) ohnehin etwas Besseres — die funktionieren nämlich zur Laufzeit und lassen sich per Dark Mode umschalten, was eine Sass-Variable nie konnte.
Du hast ein Projekt, bei dem der Build-Schritt mehr Ärger macht als er bringt? Manchmal lohnt sich der Rückbau. Schreib mir, ich sage dir ehrlich, ob es sich in deinem Fall rechnet.
Quellen
Du brauchst mehr als ein Snippet?
Ich entwickle Android-Apps in Kotlin und moderne Websites für Selbstständige und kleine Unternehmen — von der ersten Idee bis zum Release.
Projekt anfragen →Verwandte Snippets
accent-color – Checkboxen und Regler in deiner Markenfarbe, in einer Zeile
Checkboxen und Radiobuttons waren jahrelang der Grund, warum Leute sie mit appearance: none nachgebaut haben – und dabei die Tastaturbedienung verloren. Eine einzige CSS-Eigenschaft macht das überflüssig.
Text nach drei Zeilen abschneiden – line-clamp statt JavaScript
Kartenlisten sehen nur dann ordentlich aus, wenn alle Vorschautexte gleich hoch sind. Das serverseitig auf 120 Zeichen zu kürzen geht schief, sobald die Karte schmaler wird – CSS kann das seit Jahren selbst.
:focus-visible – der Fokusrahmen, den nur Tastaturnutzer sehen
outline: none ist der meistkopierte und schädlichste CSS-Schnipsel überhaupt: Danach kann niemand mehr per Tastatur navigieren. :focus-visible löst genau das Problem, das man damit lösen wollte – ohne den Schaden.