CSS-Regeln und ihre Gewichtung können für Anfänger verwirrend sein. In diesem Beitrag stelle ich dir eine Technik vor, mit der du die Gewichtung beeinflussen kannst: die CSS Cascade Layers. Durch die CSS Cascade Layers haben wir eine neue Möglichkeit, die Gewichtungen zu beinflussen – quasi ein Geschenk der "Götter". Warum das so ist und welche Möglichkeiten wir mit Layers haben, erkläre ich in diesem Artikel! Cascade Layers ermöglichen nicht nur eine bessere Kontrolle, sondern beeinflussen auch die Lesbarkeit – sowohl positiv als auch negativ.
@layer base, content;
@layer content{
body{
background: green;
}
}
@layer base{
body{
background: red;
}
}
Welche Farbe hat der Hintergrund des Bodys? Ausgehend von unserem allgemeinen Verständnis und ohne das Konzept der Cascade Layers würden wir die Farbe Rot erwarten, da sie zuletzt definiert wurde, oder? Korrekt – ohne Layer wäre unser Hintergrund rot. Allerdings haben wir hier die Cascade Layers, und in der ersten Zeile haben wir die Layers definiert: zuerst das "Base"-Layer, dann das "Content"-Layer. Entsprechend ist die vom Browser gewählte Farbe Grün.
Die CSS-Layer, die ich in diesem Beitrag vorstelle, beeinflussen nicht die Spezifität von Selektoren, haben aber einen nicht unerheblichen Einfluss darauf, welche Styles greifen. Weshalb es hilft, ein Verständnis der Spezifität zu haben, um diesen Artikel zu verstehen. Vereinfacht kann man sagen, zuerst greifen die kaskadierenden Layer und anschließend die konkreten Spezifitäten.
Unter CSS-Spezifität versteht man die Gewichtung, die bestimmt, welcher Selektor die höchste Priorität hat. Dadurch wird festgelegt, welche Styles angewendet werden. Falls dir der Begriff CSS-Spezifität nicht bekannt sein sollte, empfehle ich dir, den Artikel "CSS Spezifität - Gewichtung von CSS Selektoren erkennen" zu lesen, da dort einige Grundlagen erklärt werden.
Wir haben oben bereits ein kurzes Beispiel gesehen. Durch die Cascade Layers gibt es eine neue At-Rule @layer
, mit der wir unsere Ebenen (Layers) definieren können. Diese Layers geben uns mehr Kontrolle über die Cascade und ermöglichen es uns, besser zu definieren, welche Styles wann greifen. Dadurch können wir beispielsweise CSS-Frameworks stets niedriger gewichten als unsere eigenen Styles.
Ein wichtiger Punkt beim Verständnis von CSS-Layern ist, wie die Reihenfolge der Layers in der Cascade definiert wird. Dabei gilt: Sobald ein Layer-Name einmal verwendet wurde, ist die Position festgelegt. Angesichts dessen funktioniert auch unser Beispiel in der Einleitung: Wir definieren zuerst in der ersten Zeile unseres Stylesheets die Positionen, und anschließend haben wir unsere Layers mit den eigentlichen Styles. Würden wir diese Definition weglassen, hätten wir zuerst den content
- und dann den base
-Layer, so wie es die Cascade darstellt.
Für die Priorisierung der verschiedenen Ebenen habe ich eine Infografik vorbereitet. Diese zeigt wunderschön, wie die Layers sortiert sind. Was wir hier gut erkennen können, ist, dass die eigenen Ebenen zunächst eine geringere Priorität haben als die regulären Styles ohne Ebene. Eine weitere Besonderheit, die etwas irritierend sein mag, ist folgende: Haben wir bewusst eine Ebene sehr gering priorisiert, verwenden dort aber ein !important
, dann übergeht dies auch die höher priorisierten Ebenen mit einem !important
. Im ersten Augenblick würde man vermutlich erwarten, dass die Reihenfolge identisch ist. Aber wenn wir einmal darüber nachdenken, ergibt dieses Verhalten vollkommen Sinn. Denn wenn wir ein Styling mit !important
überschreiben wollen, müssen wir diese Ebene am höchsten priorisieren.
Oben hatte ich davon gesprochen, dass wir unsere Frameworks, deren Styles wir leicht überschreiben wollen, einfach in eine tiefere (geringere Priorität) Ebene setzen könnten. Allerdings, wenn wir ein Framework verwenden, das häufig mit !important
arbeitet, kann das uns einen Strich durch die Rechnung machen. Hier müssen wir aufpassen, weil wir diese Styles über unsere Ebene dann nicht überschrieben bekommen, auch nicht mit einem !important
. In diesem Fall wäre es hilfreich, unterhalb noch eine Ebene zu haben, in der wir diese Styles mit !important
wieder überschreiben könnten.
Wir haben nun schon einige Optionen kennengelernt, wie wir mit Cascade Layers innerhalb von Stylesheets arbeiten können. Aber was ist, wenn wir unser CSS auf mehrere Dateien aufteilen wollen? Können wir diese dann in spezifische Layers laden? Ja, das können wir. Ein schönes Beispiel dafür ist das Zurücksetzen der User-Agent-Definitions. Diese sind üblicherweise die Browser-Default-Styles. Aber wäre es nicht schön, diese in einer getrennten Ebene zu haben, sodass sie allgemein immer eine etwas niedrigere Priorität haben, unabhängig vom Selektor?
@layer reset, base, content;
@import url('reset.css') layer(reset);
@layer content{
...
}
@layer base{
...
}
h1{
font-size: 3rem;
}
Ich habe das Beispiel einmal erweitert, um das Verhalten zu demonstrieren. Im Browser werden wir die Abschnitte "User Agent Stylesheet", "Reset" und die normalen Styles sehen. Die reset.css
habe ich als Reset-Layer importiert und dort einfach ein paar Eigenschaften definiert, die mich immer wieder stören. Zum Beispiel, dass der Browser standardmäßig kein box-sizing: border-box
verwendet.
Wenn wir uns nun einmal unsere Styles anschauen, sehen wir, dass wir dort zuerst den "Reset"-Layer definieren müssen. Anschließend können wir den Import einem spezifischen Layer zuweisen. Alles, was wir jetzt regulär in unserer CSS-Datei definieren, wird immer höher gewichtet sein als der Inhalt der importierten Datei, es sei denn, wir verwenden !important
.
Wir können das Importieren von CSS-Dateien in bestimmte Layers noch weiter treiben, indem wir das Ganze auch von Media Queries abhängig machen. Dies könnte zum Beispiel nützlich sein, wenn wir spezifische Desktop- oder Mobile-Styles haben. In diesem Beispiel werden die Styles zum Zurücksetzen für Mobile nur geladen, wenn die Bildschirmbreite unter 600 Pixeln liegt.
@import url('reset-mobile.css') layer(reset) (max-width: 600px);
Persönlich halte ich es nicht für sonderlich sinnvoll, für Desktop und Mobile getrennte Styles bereitzustellen, da ich es lieber in kurzen, aufeinander aufbauenden Abschnitten lese. Eine bessere Verwendung für die Kombination von Media Queries und Cascade Layers könnte etwa sein, wenn wir einen Accessibility-Layer erstellen wollen, der immer die höchste Priorität hat.
@layer reset, base, content, accessibility;
@import url('high-contrast.css') layer(accessibility) (prefers-contrast: high);
@import url('dark-mode.css') layer(accessibility) (prefers-color-scheme: dark);
@import url('reduced-motion.css') layer(accessibility) (prefers-reduced-motion: reduce);
So können wir auf Wunsch des Nutzers in diesem Layer zusätzliche Styles für eine bessere Barrierefreiheit bereitstellen, zum Beispiel, wenn der Nutzer einen hohen Kontrast oder weniger Animationen bevorzugt.
Was darf nicht fehlen, wenn es schon Cascade Layers gibt? Genau, verschachtelte Cascade Layers! Durch die verschachtelten Cascade Layers können wir unser CSS noch besser strukturieren. Was wäre zum Beispiel, wenn jede Komponente eine eigene CSS-Datei bekäme und wir diese in eigene Layers unterhalb eines Komponenten-Layers importieren würden? Persönlich sehe ich die Verschachtelung vor allem als großen Vorteil in der Organisation von CSS, um einen besseren Überblick zu gewinnen. So haben wir zum Beispiel alle unsere Komponenten gruppiert; alternativ wird diese Option auch als "Grouped Layers" bezeichnet.
@layer reset, base, components, utilities;
@import url('reset.css') layer(reset);
@import url('base.css') layer(base);
@layer components {
@layer button{}
@layer card{}
}
@import url('utilities.css') layer(utilities);
@import url('additional-card.css') layer(components.card);
Wie in Zeile 13 zu sehen, können wir auch in ein spezifisches Sublayer bei Bedarf zusätzliche CSS-Styles importieren. Dies ist zum Beispiel dann interessant, wenn wir Komponenten haben, die Third-Party-Styles benötigen, oder wenn wir jeder Komponente eine eigene CSS-Datei spendieren wollen.
Über den Browser-Support brauchen wir uns keinerlei Sorgen mehr zu machen. Alle großen Major-Browser – Chrome, Firefox, Edge und Safari – unterstützen die Cascade Layers uneingeschränkt. Es gibt keinen Grund, sich mit dieser neuen Funktion nicht einmal auszuprobieren. Auch laut dem Baseline-Programm ist dieses Feature "widely available across major browsers".
Je mehr ich mich mit den modernen Funktionen von CSS beschäftige, wie etwa der Verschachtelung in CSS im vorherigen Artikel, frage ich mich immer mehr, ob wir überhaupt noch Präprozessoren brauchen oder ob wir sie endgültig ins Archiv verabschieden können. Es würde dazu führen, dass wir keine Build-Tools mehr benötigen – zumindest für CSS – und es einfach direkt an unsere Nutzer ausliefern könnten. Wenn ich demnächst ein neues Projekt anfange, werde ich es bestimmt mal ausprobieren. Auf einem weißen Blatt Papier lässt sich das sicherlich besser erproben.
Hinterlasse mir gerne einen Kommentar zum Artikel und wie er dir weitergeholfen hat beziehungsweise, was dir helfen würde das Thema besser zu verstehen. Oder hast du einen Fehler entdeckt, den ich korrigieren sollte? Schreibe mir auch dazu gerne ein Feedback!
Es sind noch keine Kommentare vorhanden? Sei der/die Erste und verfasse einen Kommentar zum Artikel "Effizientes Styling: CSS Layers für mehr Ordnung und Gewicht "!