Startseite / Artikel / Von Stylesheet zu Bildschirm: Wo CSS in der Browser-Pipeline seinen Platz hat

Von Stylesheet zu Bildschirm: Wo CSS in der Browser-Pipeline seinen Platz hat

Von der Herunterladung bis zu den Pixeln – CSS im Detail: Wie DOM, CSSOM und der Render-Tree erstellt werden, wo die Kaskadierung stattfindet und welche Stilquellen um jedes Element konkurrieren.

1733 Wörter

Die meisten Entwickler schreiben CSS intuitiv: Sie ändern eine Eigenschaft, laden neu und prüfen das Ergebnis. Das funktioniert, bis eine Regel aus unerklärlichen Gründen nicht angewendet wird, eine Seite ungeformatsten Inhalt anzeigt oder eine „einfache“ Änderung des Styles das Scrollen verlangsamt. Jedes dieser Probleme wird leichter zu verstehen, sobald man weiß, was der Browser tatsächlich zwischen dem Empfang einer Stylesheet-Datei und dem Darstellen der Pixel tut.

Dieser Leitfaden verfolgt diesen Prozess in groben Zügen. Sie werden sehen, wie der Browser HTML in das DOM umwandelt, wie Stylesheets zum CSSOM werden, wie die beiden zu einem Renderbaum kombiniert werden, wo Konflikte zwischen den Deklarationen gelöst werden und welche Stilquellen um jedes Element konkurrieren. Es handelt sich dabei auch um eine häufige Vorstellungsfrage, meist formuliert als „Wie funktioniert CSS im Hintergrund?“, und die untenstehende Antwort bietet Ihnen eine strukturierte Art, darauf zu antworten.

Schritt eins: HTML wird zum DOM

Wenn Sie eine URL öffnen, erhält der Browser zunächst das HTML-Dokument. Er analysiert die Markup-Struktur von oben nach unten und erstellt dabei das Document Object Model. Das DOM ist ein Baum, der das gesamte Dokument darstellt: Jedes Element ist ein Knoten, und die Knoten sind miteinander als Eltern, Kinder und Geschwister verbunden – ähnlich wie in einem Stammbaum. Alles, was im HTML beschrieben wurde, befindet sich nun in dieser Struktur, und genau diese wird auch von JavaScript gelesen und verändert.

Die Analyse erfolgt schrittweise. Der Browser wartet nicht auf das gesamte Dateiinhalt, bevor er mit dem Erstellen der Knoten beginnt; deshalb kann er bereits lange vor Abschluss des Downloads weitere Ressourcen entdecken.

Schritt zwei: Stylesheets werden zum CSSOM

Beim Parsen der HTML-Datei stößt der Browser auf Stylesheets – egal, ob sie über <link rel="stylesheet"> im Head-Bereich verknüpft sind oder in <style>-Elementen eingebettet sind – und beginnt auch deren Herunterladen sowie Parsen. CSS wird in seine eigene baumförmige Struktur umgewandelt, das CSS Object Model, oder CSSOM. Es übernimmt für Styles dieselbe Rolle wie das DOM für die Markup-Struktur.

Die Umwandlung von CSS in Styles, die für ein Element verwendet werden können, erfordert mehr Arbeit als die Umwandlung von HTML in Knoten. Zwei Aufgaben sind dabei besonders wichtig:

  1. Konflikte lösen. Oft beziehen sich mehrere Deklarationen auf dieselbe Eigenschaft desselben Elements. Der Browser klärt diese Konflikte mithilfe eines Algorithmus namens Cascade.
  • Auswertung der endgültigen Werte. Die Gewinnerangabe kann 2em, 50% oder inherit enthalten, was der Layout-Engine noch nicht zur Verfügung steht. Der Browser wandelt diese Angaben in konkrete Werte um.
  • Strikt genommen ist das CSSOM die analysierte Darstellung der Stylesheets, wobei die Kaskadierung sowie die Berechnung der Werte stattfinden, wenn der Browser den Stil jedes Elements berechnet. Für ein mentales Modell ist es jedoch in Ordnung, sich vorzustellen, dass „CSS analysiert wird, Konflikte gelöst werden, die Werte endgültig festgelegt werden und das Ergebnis den Elementen zugeordnet wird“.

    Eine praktische Folge: Da der Browser Styles benötigt, bevor er etwas Sinnvolles darstellen kann, werden Stylesheets im Head-Bereich erst dann gerendert, nachdem sie geladen und analysiert wurden. Deshalb verzögern große, langsame Stylesheets die erste Anzeige und ist es daher wichtig, kritische CSS-Dateien klein zu halten, um die Leistung zu verbessern.

    Schritt drei: DOM und CSSOM werden zum Renderbaum zusammengeführt

    Sobald die Markup-Elemente in den DOM und die Styles in den CSSOM umgewandelt wurden, fügt der Browser beides zu einem Renderbaum zusammen. Der Renderbaum enthält die Knoten, die tatsächlich angezeigt werden, wobei jeder Knoten mit seinen berechneten Styles verknüpft ist. Knoten, die keine visuelle Ausgabe liefern, wie zum Beispiel der Inhalt von <head> oder Elemente mit display: none, werden weggelassen.

    Zu diesem Zeitpunkt weiß der Browser, was angezeigt werden soll und wie jedes Element gestylt ist, kennt aber noch nicht den genauen Platz oder die Größe der Elemente.

    Schritt vier: Layout und das visuelle Formatierungsmodell

    Um gestaltete Knoten in positionierte Kästchen umzuwandeln, folgt der Browser dem sogenannten visuellen Formatierungsmodell gemäß den CSS-Spezifikationen. Dieser Teil der CSS-Spezifikation beschreibt, wie die Elemente des Dokumentbaums für visuelle Medien wie den Bildschirm eines Laptops oder Telefons angeordnet werden. Er umfasst das Kästchenmodell, Block- und Zeilenformatierung, Schwebefunktionen, Positionierung sowie weitere Regeln, die die Größe und Position jedes Kästchens bestimmen.

    Sobald das Layout die Geometrie für jedes Kästchen berechnet hat, malt der Browser sie aus, füllt Texte, Farben, Ränder, Bilder und Schatten ein, und das Endergebnis erscheint schließlich auf dem Bildschirm.

    Der gesamte Ablauf in einem Überblick

    Die Zusammenfassung der einzelnen Schritte ergibt eine einfache Abfolge vom Markup bis zu den Pixeln. Jeder Pfeil verbirgt eine beträchtliche Menge an Arbeit, doch die Reihenfolge ist entscheidend, um Fehler und Leistung zu analysieren:

    HTML
      ↓
    DOM
      ↓
    CSS
      ↓
    CSSOM
      ↓
    DOM + CSSOM
      ↓
    Render Tree
      ↓
    Layout
      ↓
    Paint
      ↓
    Pixels on the Screen
    

    Reale Browser überlappen diese Schritte und fügen weitere hinzu (zum Beispiel Kompositierschichten), und das Später Ändern eines Stils kann den Browser dazu bringen, je nach Eigenschaft die Styles erneut zu berechnen, das Layout neu anzulegen oder neu auszumalen. Für eine genaue Betrachtung dieser Kosten siehe was jede CSS-Änderung den Browser kostet.

    Warum es zu Konflikten bei Deklarationen kommt

    Der Rest dieses Leitfadens konzentriert sich auf die erste der beiden CSS-Verarbeitungsaufgaben: die Konfliktlösung. Der dafür verantwortliche Algorithmus ist die Kaskade. Sie kombiniert alle Stylesheets, die auf ein Dokument anwendbar sind, und entscheidet immer dann, welche Angabe vorherrscht, wenn mehrere Deklarationen dieselbe Eigenschaft für dasselbe Element festlegen.

    Konflikte sind unvermeidlich – und das nicht nur, weil Ihre eigene Stylesheet-Datei die Eigenschaft color an einer Verlinkung an zwei Stellen festlegen könnte. Styles stammen aus mehreren unabhängigen Quellen, sogenannten Ursprungsquellen, und alle wirken gleichzeitig auf dieselben Elemente.

    Autor-Styles

    Dies sind die Deklarationen, die Sie und Ihr Team schreiben: Ihre Stylesheets, <style>-Blöcke sowie inline-style-Attribute. Auf den meisten Webseiten stellen sie bei weitem die größte Quelle für Regeln dar.

    Benutzer-Styles

    Die Person, die die Seite ansieht, kann ebenfalls die Styles beeinflussen. Browser ermöglichen es den Nutzern, Einstellungen wie die Standard-Schriftgröße anzupassen, und einige unterstützen außerdem benutzerdefinierte Stylesheets oder Erweiterungen, die diese einfügen. Diese Präferenzen sind besonders wichtig für die Barrierefreiheit, denn sie ermöglichen Lesern mit eingeschränktem Sehvermögen oder Lesebeschwerden, eine Seite ihren Bedürfnissen anzupassen.

    User-Agent-Styles

    Zuletzt liefert der Browser (der User Agent) sein eigenes Standard-Stylesheet mit. Deshalb erscheint ein ungestyltes <a>-Element blau und unterstrichen, warum Überschriften fettgedruckt und größer als der Textkörper sind sowie warum <body> einen kleinen Rand aufweist. Diese Standards werden als User-Agent-Styles bezeichnet.

    Wenn die Kaskade alle drei Quellen zusammenführt, kann dieselbe Eigenschaft am selben Element leicht mehrere konkurrierende Werte erhalten, und der Browser benötigt eine deterministische Methode zur Auswahl.

    Wie die Kaskade entscheidet

    Die Kaskade vergleicht widersprüchliche Deklarationen mithilfe einer festgelegten Reihenfolge von Kriterien und wechselt erst zum nächsten Kriterium, wenn das vorherige zu einem Gleichstand führt:

    1. Ursprung und Wichtigkeit. Woher die Deklaration stammt und ob sie mit !important markiert ist.
    2. Spezifität. Wie präzise der Selektor das Element anspricht; ein ID-Selektor hat Vorrang vor einem Klassen-Selektor, der wiederum Vorrang vor einem Typ-Selektor hat.
    3. Reihenfolge der Quellen. Wenn alles andere gleich ist, gewinnt die später auftretende Deklaration.

    Rangordnung der Ursprünge

    Für das erste Kriterium gilt die klassische Prioritätsreihenfolge von höchster zu niedrigster Stufe wie folgt:

    1. Von Benutzern markierte Deklarationen mit !important.
    2. Von Autoren markierte Deklarationen mit !important.
    3. Normale Autoren-Deklarationen.
  • Normale Benutzerdeklarationen.
  • Deklarationen des User-Agents (Browser-Standard).
  • Bemerken Sie, was das bedeutet. Ihre normalen Styles überschreiben die üblichen Präferenzen des Benutzers sowie die Browser-Standardeinstellungen – genau das ermöglicht es Ihnen überhaupt, eine Seite zu gestalten. Doch !important kehrt die Reihenfolge zwischen Benutzern und Erstellern um: Ein Benutzer, der tatsächlich eine größere Schriftgröße oder einen höheren Kontrast benötigt, kann diese Präferenz als wichtig markieren und selbst Ihre !important-Regeln überschreiben. Die eigenen Browser-Standardeinstellungen kommen ganz zum Schluss und gelten nur, wenn niemand anderes etwas angegeben hat.

    Modernes CSS verfeinert dieses Konzept. Die aktuelle Kaskadierung berücksichtigt außerdem Kaskaden-Ebenen (@layer), durch laufende Animationen und Übergänge gesetzte Styles sowie !important-Deklarationen von User-Agents, die über allen anderen wichtigen Deklarationen rangieren. Die oben gezeigte vereinfachte Liste fasst weiterhin die am häufigsten relevanten Beziehungen zusammen; für die vollständige Reihenfolge sollten Sie sich die früher verlinkte MDN-Kaskadierungsreferenz ansehen.

    Spezifität und Quellreihenfolge verdienen eine eigene ausführliche Behandlung, einschließlich der Art und Weise, wie Selektor-Gewichte verglichen werden, sowie des Grundes, warum !important so oft mehr Probleme verursacht als löst. Dies wird in „Wie die Kaskadierung einen Gewinner auswählt“ erläutert.

    Warum dieses Wissen lohnenswert ist

    Das Verständnis des Ablaufs verändert Ihre Vorgehensweise bei der Fehlersuche und beim Schreiben von Styles:

    • Nicht anwendbare Regeln sind fast immer Kaskadenverluste. Die Kenntnis der Reihenfolge von Ursprung, Spezifität und Quellreihenfolge zeigt Ihnen an, wo Sie suchen sollten, anstatt auf !important zurückzugreifen.
    • Aufblitze ungestylten oder spät gestylten Inhalts entstehen durch die render-blockierende Wirkung von Stylesheets sowie durch Styles, die nach der ersten Darstellung eintreffen.
    • Störende Interaktionen gehen oft auf Änderungen zurück, die dazu führen, dass Layout oder Zeichnen erneut ausgeführt werden – dies können Sie vermeiden, sobald Sie wissen, in welcher Phase eine Eigenschaft wirkt.
    • Wartbarer CSS weist in der Regel eine niedrige, vorhersehbare Spezifität sowie eine klare Quellreihenfolge auf, was sowohl für den Browser als auch für Ihre Kollegen leichter zu verarbeiten ist.

    Zusammenfassung

    Der Browser wandelt HTML in das DOM und Stylesheets in das CSSOM um, kombiniert sie zu einem Darstellungsbaum aus sichtbaren, gestalteten Knoten und verwendet anschließend das visuelle Formatierungsmodell, um die Boxen anzuordnen, bevor sie dargestellt werden. In der CSS-Phase ist die Kaskadierung der erste Kontrollmechanismus: Sie fügt die Styles des Autors, des Benutzers und des User-Agents zusammen und löst alle Konflikte zunächst nach ihrer Herkunft und Bedeutung, dann nach der Spezifität sowie schließlich nach der Reihenfolge der Quellen. Die nächste Phase, bei der die gewonnenen Werte in konkrete Zahlen umgewandelt werden, die vom Layout-Engine verwendet werden können, wird in wie Browser CSS-Werte vor der Layout-Erstellung auflösen erläutert.