Was macht ein Browser eigentlich genau?
Ein Browser ist eine Ausführungsumgebung und nicht bloß ein Dokumentenbetrachter. Er parst HTML und CSS in Bäume, führt JavaScript aus, stellt APIs für Networking und Storage bereit und rendert das Ergebnis in Pixel. Wenn man diese Pipeline versteht, wird Performance-Optimierung von bloßem Raten zu echtem Engineering.
Die Browser-Hersteller liefern drei Haupt-Engines aus: Blink (Chrome, Edge, Opera), Gecko (Firefox) und WebKit (Safari). Diese implementieren dieselben Standards, sodass die hier beschriebenen Konzepte überall gelten, auch wenn die Details variieren mögen.
HTML in das DOM parsen
Wenn der Browser HTML empfängt, parst er es in das DOM: einen Baum aus Objekten, die jedes Element, Attribut und Textstück repräsentieren. Der Parser arbeitet als Stream, sodass er mit dem Aufbau des Baums beginnen kann, noch bevor das gesamte Dokument eingetroffen ist.
Das HTML-Parsing ist von Haus aus fehlertolerant. Ein fehlender schließender Tag oder ein falsch platziertes Element stoppt die Seite nicht; der Parser erholt sich davon und macht weiter. Aus diesem Grund wird auch fehlerhaftes Markup dennoch gerendert – und genau deshalb ist die Validierung Ihres HTML für die Vorhersehbarkeit des Ergebnisses so wichtig.
CSS und das CSSOM
Stylesheets werden in das CSSOM geparst, einen Baum aus Regeln. Der Browser berechnet anschließend den finalen Style jedes Elements, indem er die Kaskade, Vererbung und Spezifität kombiniert.
CSS ist render-blocking: Der Browser führt kein Painting durch, bis er die benötigten Styles hat, da ein Painting mit falschen Styles zu einem sichtbaren Flackern führen würde. Aus diesem Grund verzögert ein großes Stylesheet im Head den First Paint, und weshalb das Inlining von kritischem CSS hilfreich ist.
Der Render Tree
Das DOM und das CSSOM verschmelzen zum Render Tree. Dieser enthält nur die Elemente, die tatsächlich angezeigt werden, jeweils zusammen mit ihren berechneten Styles. Elemente mit display: none werden ausgeschlossen; visibility: hidden-Elemente werden zwar aufgenommen, aber nicht gezeichnet.
An diesem Punkt weiß der Browser, was gezeichnet werden muss, aber noch nicht, wo.
Layout
Layout, auch als Reflow bezeichnet, berechnet die Größe und Position jeder Box im Render Tree. Dabei wird der Baum durchlaufen, um Breiten, Höhen, Margins, Padding und die Positionierung aufzulösen, woraus ein Box-Modell mit exakter Geometrie resultiert.
Layout ist rechenintensiv, da Änderungen kaskadieren können: Das Ändern der Größe eines Elements kann dessen Geschwisterelemente, das Elternelement und alles darunter verschieben. Das Auslesen von Eigenschaften wie offsetHeight zwingt den Browser dazu, sicherzustellen, dass das Layout aktuell ist. Wenn Lese- und Schreibzugriffe abwechselnd erfolgen, löst dies wiederholte Layout-Berechnungen aus.
Paint und Composite
Nach dem Layout paint (zeichnet) der Browser die Boxen in Layer und füllt Farben, Texte, Bilder, Rahmen und Schatten aus. Anschließend werden diese Layer composited (zusammengeführt), oft auf der GPU, um den finalen Frame zu erzeugen.
Einige Änderungen sind weniger rechenintensiv als andere:
- Eine Farbänderung löst ein Paint aus.
- Eine Größenänderung löst Layout und Paint aus.
- Änderungen an
transformoderopacitykönnen vom Compositor verarbeitet werden, wodurch Layout und Paint komplett übersprungen werden.
Aus diesem Grund sollten Animationen auf Transforms und Opacity beschränkt bleiben. Siehe dazu den CSS Animations Guide und den Web Performance Guide.
Der Critical Rendering Path
Der Weg von HTML bis zu den ersten Pixeln sieht so aus:
- Parse: HTML wird in das DOM umgewandelt.
- Parse: CSS wird in das CSSOM umgewandelt.
- Combine: Beide werden zum Render Tree kombiniert.
- Layout: Die Boxen werden angeordnet.
- Paint und Composite: Der Frame wird gezeichnet und zusammengesetzt.
Die Verkürzung dieses Pfades ist der Kern der wahrgenommenen Performance: weniger blockierende Ressourcen, kleineres CSS und JavaScript, das den Prozess nicht behindert.
<!-- fast.html -->
<link rel="preload" href="/fonts/inter.woff2" as="font" type="font/woff2" crossorigin />
<style>/* critical, above-the-fold CSS */</style>
<script src="/app.js" defer></script>
preload startet wichtige Anfragen frühzeitig, inlined critical CSS vermeidet einen blockierenden Roundtrip und defer erlaubt es dem Parser, die Arbeit abzuschließen, bevor das Script ausgeführt wird.
Der Main Thread und JavaScript
Der Main Thread führt JavaScript, Layout, Paint und die Event-Verarbeitung aus. Da immer nur eine Sache gleichzeitig passiert, blockiert ein langwieriger Task die Eingaben und lässt die Seite eingefroren wirken.
- Halten Sie Tasks kurz und teilen Sie rechenintensive Arbeit auf.
- Verlagern Sie schwere Berechnungen in einen Web Worker, der in einem separaten Thread läuft.
- Vermeiden Sie Layout Thrashing, indem Sie DOM-Reads und -Writes bündeln.
- Geben Sie zwischen Arbeitspaketen die Kontrolle an den Browser zurück (Yielding).
Dies ist derselbe Event Loop, den Sie bereits im JavaScript-Guide kennengelernt haben – nur dass nun auch die Rendering-Aufgaben um denselben Thread konkurrieren.
Storage und Browser-APIs
Neben dem Rendering stellt der Browser verschiedene Storage- und Plattform-APIs bereit: Cookies, localStorage und sessionStorage, IndexedDB, die Cache API, Service Worker, WebSockets, WebRTC, die Clipboard-API, Notifications und mehr. Diese ermöglichen es einer Webseite, sich wie eine Anwendung zu verhalten. Der PWA-Guide befasst sich ausführlich mit Service Workern und Caching.
Best Practices
- Halten Sie den critical path kurz: Binden Sie kritisches CSS inline ein und verzögern Sie das Laden von Scripts.
- Verwenden Sie
preloadfür Fonts und andere render-kritische Assets. - Animieren Sie transform und opacity, keine Layout-Properties.
- Bündeln Sie DOM-Reads und -Writes, um Layout Thrashing zu vermeiden.
- Halten Sie JavaScript-Tasks kurz; nutzen Sie Web Workers für rechenintensive Aufgaben.
- Reservieren Sie Platz für Bilder und Embeds, um Layout Shifts zu vermeiden.
- Testen Sie in verschiedenen Engines, insbesondere in Safari und auf mobilen Geräten.
Häufige Fehler
- Die Annahme, dass das DOM identisch mit dem HTML-Quelltext ist.
- Blockieren des Renderings durch große Stylesheets oder synchrone Scripte.
- Auslesen von Layout-Properties innerhalb einer Schleife, was zu wiederholten Reflows führt.
- Animieren von
widthodertop, was Ruckler (Jank) verursacht. - Ausführen rechenintensiver Operationen auf dem Main Thread.
- Testen in nur einem einzigen Browser, wodurch Unterschiede zwischen den Engines übersehen werden.
Wie geht es weiter?
Die Browser-Internals erklären, warum Performance-Tipps überhaupt funktionieren. Setze dieses Wissen mit dem Web Performance Guide in die Praxis um, erstelle effiziente Animationen mit CSS Animations und manipuliere den Tree sicher mittels DOM Manipulation. Öffne anschließend die DevTools und beobachte die Rendering-Pipeline im Performance-Panel.