Zum Inhalt springen
Frontend-Optimierung

Style-Recalculation: wenn CSS erst im Browser bremst

Warum Stilberechnung zur Laufzeit Zeit kostet, wie Selector Stats und Long Animation Frames den Anteil sichtbar machen und welche Eingriffe den Umfang senken.

14 Min. Lesezeit CSSRenderingINPFrontend

CSS gilt als der billige Teil einer Seite. Gemessen an den Bytes stimmt das: Die mediane mobile Startseite liefert 77 KB (Web Almanac 2025) an Stylesheets aus, gegenüber 632 KB (Web Almanac 2025) JavaScript. Gemessen an der Zeit, die der Hauptprozess damit verbringt, stimmt es nicht mehr. Jede Klassenänderung, jedes Aufklappen, jedes Umschalten eines Zustands zwingt den Browser dazu, für die betroffenen Elemente die berechneten Stile neu zu bestimmen – und dieser Schritt liegt in derselben Frist wie die Antwort auf den Klick. Ein gutes INP-Ergebnis setzt voraus, dass 75 Prozent (Web Almanac 2025) der Sitzungen bei 200 Millisekunden (Web Almanac 2025) oder darunter liegen; in dieser Frist sitzt die Stilberechnung mit drin. Dieser Beitrag zeigt, woraus die Kosten bestehen, wie man sie im Labor und im Feld sichtbar macht und welche Eingriffe den Umfang der Neuberechnung tatsächlich verkleinern. Wo die Zeit auf einer konkreten Seite bleibt, klärt eine technische Performance-Analyse.

Das Wichtigste in Kürze

  • Die Stilberechnung hat zwei Kostentreiber: das Suchen passender Regeln und das Zusammenbauen des Ergebnisses. Rund die Hälfte der Zeit entfällt in der Rendering-Engine von Chromium auf das Zuordnen der Selektoren (web.dev).
  • Die obere Schranke der Kosten ist das Produkt aus der Zahl der Elemente und der Zahl der Selektoren (web.dev). Beide Faktoren wachsen unabhängig voneinander – und beide lassen sich getrennt verkleinern.
  • Der Bestand liefert die Größenordnung: Im Median trägt eine mobile Seite 613 (Web Almanac 2022) Stilregeln, im 90. Perzentil sind es 2.023 (Web Almanac 2022). Verteilt wird das über 8 (Web Almanac 2025) CSS-Dateien im Median.
  • Im Labor macht die Registerkarte Selector Stats die teuren Regeln sichtbar: Sie zeigt neben der Zeit auch Trefferversuche und tatsächliche Treffer – ein Selektor mit 1.104 (Chrome for Developers) Versuchen ohne einen einzigen Treffer ist reine Verlustarbeit.
  • Im Feld liefert die Long-Animation-Frames-Schnittstelle mit styleAndLayoutStart den Beginn der Stil- und Layoutphase innerhalb eines Rahmens (Chrome for Developers). Damit lässt sich der Anteil belegen, statt ihn zu vermuten.
  • Der Umfang folgt der Knotenzahl: Der DOM-Prüfpunkt warnt ab rund 800 (Lighthouse) Knoten im Körper der Seite und meldet einen Fehler ab rund 1.400 (Lighthouse) Knoten.

Was der Browser tut, bevor etwas sichtbar wird

Zwischen einer Zustandsänderung im Skript und dem nächsten Bild auf dem Schirm liegen vier Arbeitsschritte: Stilberechnung, Layout, Zeichnen und Zusammensetzen. Der erste davon beantwortet eine scheinbar einfache Frage – welche Deklarationen gelten für dieses Element? Um sie zu beantworten, bildet die Engine zunächst die Menge der passenden Selektoren und verarbeitet anschließend deren Regeln zu einem berechneten Stil. Die Aufteilung dieser Arbeit ist dokumentiert: Rund die Hälfte der Zeit, die in der Rendering-Engine von Chromium für den berechneten Stil eines Elements aufgewendet wird, geht in das Zuordnen der Selektoren, die andere Hälfte in den Aufbau der berechneten Darstellung aus den passenden Regeln (web.dev). Wer nur an den Selektoren schraubt, hat also höchstens die halbe Rechnung im Blick.

Der zweite Teil der Rechnung ist der Umfang. Die Dokumentation formuliert die obere Schranke unmissverständlich: Im ungünstigsten Fall entspricht der Aufwand für die berechneten Stile der Zahl der Elemente multipliziert mit der Zahl der Selektoren, weil die Engine jedes Element mindestens einmal gegen jede Regel prüfen muss (web.dev). Moderne Engines unterlaufen diese Schranke mit Invalidierungssätzen je Element, doch die Richtung bleibt: Je höher im Baum eine Klasse umgeschaltet wird, desto mehr Nachkommen geraten in den Prüfbereich. Eine Klasse am body ist in der Wirkung etwas anderes als dieselbe Klasse an einer Karte in einer Liste, auch wenn im Editor beide Änderungen gleich aussehen. Warum eine große Knotenzahl an mehreren Stellen zugleich Kosten erzeugt, ordnet der Beitrag zur Reduktion der DOM-Größe ein.

Warum die Rechnung mobil härter ausfällt

Die Stilberechnung hängt an der Einkernleistung, und genau dort ist der Geräteabstand am größten. Im Labor liegt die mediane Blockadezeit auf dem Telefon bei 1.916 Millisekunden (Web Almanac 2025), auf dem Desktop bei 92 Millisekunden (Web Almanac 2025). Derselbe Selektorsatz, dieselbe Knotenzahl, dieselbe Interaktion – und trotzdem zwei völlig verschiedene Erfahrungen. Wer die Messlatte auf dem Rechner im Team ansetzt, sieht die teure Hälfte der Verteilung erfahrungsgemäß gar nicht; das ordnet der Beitrag zum Zielgerät statt Testgerät ein.

Zwei Kostenarten: Trefferversuche und Umfang

Die erste Kostenart ist gut messbar und wird selten gemessen: Trefferversuche ohne Treffer. Die Engine prüft einen Selektor gegen ein Element, stellt fest, dass er nicht passt, und verwirft das Ergebnis. Diese Arbeit taucht in keiner Deckungsanalyse auf, weil die Regel ja korrekt ungenutzt bleibt – sie kostet trotzdem Zeit. In der Beispielausgabe der Chrome-Dokumentation steht dazu ein Satz, der die Größenordnung greifbar macht: Die Engine hat versucht, diesen einen Selektor 1.104 (Chrome for Developers) Mal zuzuordnen, ohne ein einziges Element zu treffen. Solche Regeln stammen typischerweise aus Baukästen, Kampagnenvorlagen und alten Themenpaketen, die in jedem Bündel mitreisen. Wie man diesen Bestand systematisch aufräumt, beschreibt der Beitrag zum Finden und Entfernen ungenutzten CSS.

Die zweite Kostenart ist der Umfang der Invalidierung. Sie entsteht nicht im Stylesheet, sondern im Skript: an der Stelle, an der eine Klasse gesetzt, ein Attribut geändert oder eine Eigenschaft geschrieben wird. Je weiter oben der Knoten sitzt und je breiter die betroffenen Selektoren greifen, desto mehr Elemente wandern in die Neubewertung. In der Beispielaufnahme der Dokumentation zeigt der Bericht neben der Dauer auch die Zahl der betroffenen Elemente – gut 900 (web.dev) in jenem Fall, bei einer Stilberechnung von etwas über 25 Millisekunden (web.dev). Das ist kein Extremfall, sondern eine gewöhnliche Umschaltung; die 25 Millisekunden sind bereits ein Achtel der Frist, die für die gesamte Interaktion zur Verfügung steht.

KostenartWoran man sie erkenntWo sie sichtbar wirdBelegte Größenordnung
Trefferversuche ohne Trefferhohe Versuchszahl, Trefferzahl nahe nullSelector Stats in der Aufnahme1.104 Versuche, 0 Treffer (Chrome for Developers)
Regelmenge je Seiteviele Bündel, viele ThemenpaketeZahl der Stilregeln je Dokument613 im Median, 2.023 im 90. Perzentil (Web Almanac 2022)
Dateiaufteilungviele einzelne StylesheetsNetzwerkübersicht der Aufnahme8 Dateien im Median, 31 im 90. Perzentil (Web Almanac 2025)
InvalidierungsumfangUmschaltung weit oben im BaumZahl betroffener Elemente im Ereignisrund 900 Elemente bei gut 25 ms (web.dev)
Knotenzahl des Dokumentslange Listen, tiefe VerschachtelungDOM-Prüfpunkt im BerichtWarnung ab rund 800, Fehler ab rund 1.400 Knoten (Lighthouse)

Die vier Zeilen hängen zusammen, aber sie werden mit verschiedenen Werkzeugen gefunden. Regelmenge und Dateiaufteilung stehen im Bündel, die Trefferversuche stehen in der Aufnahme, der Invalidierungsumfang steht im Skript. Ein Bericht, der nur die Byte-Größe des CSS ausweist, deckt genau eine dieser vier Zeilen ab – und ausgerechnet die, die auf schnellen Verbindungen am wenigsten wehtut. Wie eine Prüfung aussieht, die alle vier Ebenen zusammenführt, zeigt unsere Frontend-Optimierung.

Wie viel CSS heute tatsächlich ausgeliefert wird

Ohne Bestandszahlen bleibt jede Empfehlung Geschmackssache, deshalb ein kurzer Blick auf die Verteilung. Für die mediane mobile Startseite werden 77 KB (Web Almanac 2025) an Stylesheets übertragen, für Unterseiten 80 KB (Web Almanac 2025). Verteilt wird diese Menge über 8 (Web Almanac 2025) CSS-Dateien im Median; im 90. Perzentil sind es 31 (Web Almanac 2025) Dateien. Die Regelmenge dahinter wurde zuletzt 2022 systematisch erhoben: 613 (Web Almanac 2022) Stilregeln je mobiler Seite im Median, 1.197 (Web Almanac 2022) im 75. und 2.023 (Web Almanac 2022) im 90. Perzentil. Diese Regeln sind die rechte Seite der Multiplikation aus der Dokumentation – und sie wachsen selten von allein zurück.

Die Verteilung ist schief

Bei den übertragenen Stylesheet-Größen lagen die Perzentile mobil 2022 bei 6, 28, 68, 139 und 256 KB (Web Almanac 2022). Zwischen dem Median und dem 90. Perzentil liegt damit fast der Faktor vier. Ein Mittelwert beschreibt diese Verteilung erfahrungsgemäß schlecht; entscheidend ist, an welcher Stelle die eigene Seite liegt.

Der Universalselektor ist Alltag

Knapp die Hälfte aller untersuchten Seiten wendet die Box-Modell-Angabe über den Universalselektor auf jedes Element an (Web Almanac 2022). Das ist als Muster verbreitet und in der Regel unkritisch, zeigt aber, wie selbstverständlich Regeln geschrieben werden, die den gesamten Baum berühren.

Die Frist ist fest

Für ein gutes INP-Ergebnis müssen 75 Prozent (Web Almanac 2025) der Sitzungen bei 200 Millisekunden (Web Almanac 2025) oder darunter liegen. In dieser Frist stecken Eingabeverzögerung, Verarbeitung und Darstellung zusammen – die Stilberechnung teilt sich das Budget mit allem anderen.

Interessant ist, wo dieser Druck zuerst sichtbar wird. Startseiten erreichen mobil zu 80 Prozent (Web Almanac 2025) ein gutes INP, Unterseiten nur zu 69 Prozent (Web Almanac 2025). Genau dort sitzen die interaktiven Flächen: Filter, Varianten, Mengenfelder, Aufklappbereiche. Wer die Startseite prüft und die Kategorieseite auslässt, misst den freundlicheren Teil des Bestands. Was das im Kaufprozess bedeutet, wo jede Umschaltung unmittelbar sichtbar wird, behandelt der Beitrag zum Checkout-Tempo in den letzten Sekunden vor der Bestellung.

Der Kern in einem Satz

Die Stilberechnung wird nicht dadurch teuer, dass ein Stylesheet groß ist, sondern dadurch, dass viele Regeln gegen viele Knoten geprüft werden – und beide Zahlen wachsen in gewachsenen Projekten unabhängig voneinander weiter, solange sie niemand ausweist.

Im Labor: Recalculate Style und Selector Stats

In einer Aufnahme des Leistungsbereichs heißt der gesuchte Eintrag Recalculate Style. Er erscheint dort, wo der Browser die berechneten Stile für einen Teil des Baums neu bestimmt, und er trägt zwei Angaben, die zusammen die Diagnose tragen: die Dauer und die Zahl der betroffenen Elemente. Werden diese Einträge lang, hilft die Registerkarte Selector Stats dabei zu verstehen, welcher der eigenen CSS-Selektoren die meiste Zeit verbraucht (Chrome for Developers). Die Tabelle führt je Selektor die verbrauchte Zeit, die Trefferversuche und die tatsächlichen Treffer – damit lässt sich Verlustarbeit von notwendiger Arbeit trennen, statt nach Gefühl zu kürzen.

Ein Detail entscheidet über die Brauchbarkeit der Messung: Selector Stats ist standardmäßig abgeschaltet, weil die Erhebung den Aufnahmen zusätzlichen Aufwand hinzufügt (Chrome for Developers). Die Absolutwerte einer Aufnahme mit eingeschalteter Statistik sind deshalb nicht mit denen einer gewöhnlichen Aufnahme vergleichbar. Für die Diagnose ist das unerheblich, weil die Rangfolge der Selektoren erhalten bleibt; für einen Vorher-Nachher-Beleg ist es entscheidend, weil sonst der Messaufbau selbst den Unterschied erzeugt. Zwei Aufnahmen, dieselbe Einstellung, derselbe Ablauf – sonst vergleicht man zwei verschiedene Messungen miteinander.

selektor-druck.js
// Grober Bestandswert vor der Aufnahme: wie viele Regeln liegen
// überhaupt im Dokument, und wie verteilen sie sich auf Blöcke?
const blaetter = [...document.styleSheets];
let regeln = 0, unlesbar = 0;

for (const blatt of blaetter) {
  try {
    regeln += blatt.cssRules.length;
  } catch (e) {
    // Fremde Herkunft ohne CORS-Freigabe: nicht lesbar, nicht raten
    unlesbar += 1;
  }
}

console.table({
  stylesheets: blaetter.length,
  regeln,
  unlesbar,
  knotenImKoerper: document.body.getElementsByTagName('*').length
});

Ein nicht lesbares Stylesheet ist kein leeres Stylesheet

Der Zugriff auf cssRules scheitert bei Stylesheets fremder Herkunft ohne entsprechende Freigabe. Wer den Fehler abfängt und stillschweigend null Regeln zählt, erhält eine Bestandszahl, die zu klein ist – und zwar genau um die Bündel, die nicht aus dem eigenen Bau stammen. Deshalb zählt das Beispiel die nicht lesbaren Blätter getrennt aus, statt sie als null zu verbuchen. Eine Zahl ohne Angabe darüber, was sie nicht enthält, ist in der Regel die teurere Variante.

Im Feld: der Rahmen als Zeitleiste

Die Laboraufnahme zeigt einen Ablauf auf einem Gerät. Ob dieselbe Umschaltung bei den Besuchern teuer ist, beantwortet sie nicht. Dafür gibt es die Schnittstelle für lange Animationsrahmen, die einen Rahmen in Zeitpunkte zerlegt: startTime markiert den Beginn, renderStart den Beginn der Darstellungsarbeit und styleAndLayoutStart den Beginn des Zeitraums, der in Stil- und Layoutberechnungen verbracht wird (Chrome for Developers). Aus der Differenz zwischen dem Ende des Rahmens und diesem Zeitpunkt ergibt sich die Dauer der Stil- und Layoutphase – in der Beispielrechnung der Dokumentation sind das 111 Millisekunden (web.dev) innerhalb eines einzigen Rahmens.

Ergänzend führt jeder erfasste Skripteintrag das Feld forcedStyleAndLayoutDuration, das die Zeit ausweist, die innerhalb dieser Funktion für erzwungene Stil- und Layoutberechnungen anfällt (Chrome for Developers). Das ist der klassische Fall, bei dem ein Ereignisbehandler schreibt und unmittelbar danach eine Geometrie ausliest und die Engine zur sofortigen Neuberechnung zwingt. Der Wert benennt den Verursacher, statt nur die Summe zu melden. Wie man aus diesen Rahmen eine belastbare Reihenfolge macht, beschreibt der Beitrag zu Long Animation Frames als INP-Bremse; die Einordnung der Kennzahl selbst steht im Beitrag zum Optimieren von INP.

loaf-stilanteil.js
// Anteil der Stil- und Layoutphase je langem Rahmen bestimmen.
// Erhoben werden nur Zeitwerte des eigenen Dokuments.
const beobachter = new PerformanceObserver((liste) => {
  for (const rahmen of liste.getEntries()) {
    const ende = rahmen.startTime + rahmen.duration;
    const stilLayout = rahmen.styleAndLayoutStart
      ? ende - rahmen.styleAndLayoutStart
      : null; // nicht gemessen, nicht null setzen

    const erzwungen = rahmen.scripts.reduce(
      (summe, s) => summe + (s.forcedStyleAndLayoutDuration || 0), 0);

    meldung({
      rahmenDauer: Math.round(rahmen.duration),
      stilUndLayout: stilLayout === null ? null : Math.round(stilLayout),
      erzwungen: Math.round(erzwungen),
      ausloeser: rahmen.scripts[0]?.invoker ?? 'unbekannt'
    });
  }
});

beobachter.observe({ type: 'long-animation-frame', buffered: true });

Was den Umfang wirklich verkleinert

Die naheliegende Antwort lautet: kürzere Selektoren. Sie ist richtig, aber sie ist die kleinere Hälfte. Die Dokumentation nennt die Zahl der neu bewerteten Elemente ausdrücklich als den oft wichtigeren Hebel gegenüber der Selektorkomplexität (web.dev). Praktisch heißt das: Eine Umschaltung, die statt am Wurzelelement an dem Container stattfindet, der die Änderung tatsächlich betrifft, verkleinert den Prüfbereich unmittelbar – ohne dass eine einzige Regel umgeschrieben werden muss. Und sie ist in der Regel schneller umgesetzt als ein Umbau des Stylesheets.

  1. Den Umschaltpunkt so tief wie möglich im Baum setzen. Eine Klasse am body zieht potenziell den gesamten Teilbaum in die Neubewertung; dieselbe Klasse am betroffenen Abschnitt bleibt lokal. Das ist eine Änderung an einer Zeile Skript, keine Umstellung des Stylesheets.
  2. Zustände über eine feste Menge von Klassen abbilden statt über Inline-Stile in einer Schleife. Wer in einer Schleife schreibt und liest, erzwingt die Neuberechnung mitten im Ereignisbehandler – genau das weist forcedStyleAndLayoutDuration aus (Chrome for Developers).
  3. Selektoren mit tiefer Verschachtelung und positionsabhängigen Pseudoklassen auf eine Klasse am Zielelement zurückführen. Die Dokumentation begründet das damit, dass die Engine für positionsabhängige Prüfungen zunächst die Geschwisterlage kennen muss (web.dev).
  4. Die Knotenzahl im Blick behalten. Der DOM-Prüfpunkt warnt ab rund 800 (Lighthouse) Knoten im Körper und meldet ab rund 1.400 (Lighthouse) Knoten einen Fehler; lange Listen ohne Auslagerung sind der häufigste Grund, diese Marken zu reißen.
  5. Bereiche außerhalb des Sichtfelds von der Darstellungsarbeit ausnehmen, statt sie mitzurechnen. Wie das mit Bordmitteln funktioniert, beschreibt der Beitrag zu content-visibility und gesparter Rendering-Arbeit.
  6. Regelmenge zurückschneiden, bevor neue Bündel dazukommen. Bei 8 (Web Almanac 2025) CSS-Dateien im Median und 31 (Web Almanac 2025) im 90. Perzentil ist die Frage selten, ob etwas fehlt, sondern welches Paket seit dem letzten Umbau ohne Aufgabe mitfährt.
  7. Den kritischen Teil vom Rest trennen, damit der erste Aufbau nicht auf das gesamte Regelwerk wartet. Das Vorgehen steht im Beitrag zu Critical CSS oberhalb der Falz.

Zwei Punkte gehören zusammen gedacht: Animationen und Stilberechnung. Eine Übergangsanimation, die eine Eigenschaft verändert, welche die Geometrie berührt, löst in jedem Bild erneut Stil- und Layoutarbeit aus. Die Zeitleiste zeigt das als Kette gleichartiger Einträge über viele Rahmen hinweg. Welche Eigenschaften sich stattdessen ohne diese Kette animieren lassen, behandelt der Beitrag zu flüssigen Animationen ohne Ruckeln. Bei Shops kommt hinzu, dass Varianten- und Filterumschaltungen häufig ganze Listen neu bewerten lassen – ein Muster, das die Shopware-Performance regelmäßig stärker prägt als die Startseite.

Im ungünstigsten Fall entspricht der Aufwand für die berechneten Stile der Zahl der Elemente multipliziert mit der Zahl der Selektoren, weil der Browser jedes Element mindestens einmal gegen jede Regel prüfen muss.

web.dev, Reduce the scope and complexity of style calculations

Zum Nachweis gehört ein zweiter Blick. Eine Laboraufnahme belegt, dass ein Selektor Zeit verbraucht; erst die Felddaten belegen, dass diese Zeit bei den Besuchern ankommt. Beide Quellen nebeneinanderzulegen ist ein eigener Arbeitsschritt, den der Beitrag zu Felddaten und Laborwerten beschreibt. Und weil die Erhebung im Feld personenbezogene Fragen berührt, gehört die rechtliche Seite in dieselbe Planung: Was ohne Einwilligung zulässig ist, klärt der Beitrag zur Performance-Messung ohne Einwilligung. Wie sich der Aufwand insgesamt auf die drei Kennzahlen verteilt, ordnet unsere Übersicht zu den Core Web Vitals ein.

Quellen und Studien

Dieser Artikel basiert auf Daten des HTTP Archive Web Almanac 2025 (Kapitel Performance und Page Weight), auf das CSS-Kapitel des Web Almanac 2022, auf die Entwicklerdokumentation von Chrome for Developers zu Selector Stats und zur Schnittstelle für lange Animationsrahmen, auf web.dev zur Reichweite und Komplexität von Stilberechnungen sowie auf die Lighthouse-Dokumentation zum DOM-Prüfpunkt. Die genannten Zahlen beziehen sich auf den Stand der jeweiligen Veröffentlichung; die Regelmengen stammen aus der Erhebung von 2022 und sind entsprechend gekennzeichnet.

Verwandte Artikel

Core Web Vitals & Messung

DOM-Größe reduzieren: weniger Knoten, mehr Tempo

DOM-Größe reduzieren: mit Pagination, Virtualisierung, content-visibility und flacherem Markup die Style- und Layout-Arbeit senken und den INP verbessern.

12 Min. Lesezeit
Frontend-Optimierung

Ungenutztes CSS finden und entfernen: schlanker laden

Wie viel CSS eine Seite braucht, wie sich der ungenutzte Anteil messen lässt und in welcher Reihenfolge sich Ballast ohne Darstellungsschäden entfernen lässt.

13 Min. Lesezeit
Frontend-Optimierung

Speicherlecks im Frontend: wenn die Seite träge wird

Die Oberfläche startet schnell und wird nach zwanzig Minuten zäh: wie Speicherlecks im Frontend entstehen, wie man sie im Verlauf misst und wieder loswird.

12 Min. Lesezeit