Wissen

Layout Shift durch Schriften: Swap behalten, den Sprung wegnehmen

Lädt der Browser die Schriften nach, springt der Text und der Cumulative Layout Shift steigt. Ursache ist der Breitenunterschied zwischen Ersatzschrift und Webfont, der Fix ein Fallback-Face mit korrigierter Metrik. Fünf Schritte führen dorthin: Befund, Ursache, Fallback-Stack, angeglichene Metrik, Abnahme. Alle Zahlen stammen aus Messungen und Rechnungen an meiner eigenen Website, keine ist recherchiert.

Was ein Layout Shift durch Schriften ist

Lädt der Browser eine Schrift nach, die breiter oder schmaler läuft als die Ersatzschrift, brechen die Zeilen neu um. Alles darunter rückt mit: Absätze, Karten, Schaltflächen. Genau das misst der Cumulative Layout Shift (CLS)Ein Maß dafür, wie stark Inhalte beim Laden noch verrutschen, nachdem sie schon sichtbar waren., eine der drei Metriken der Core Web VitalsDrei Messwerte von Google für die gefühlte Qualität einer Seite: LCP, CLS und INP.. Der Score multipliziert den Anteil des Viewports, den die verschobenen Elemente belegen, mit der zurückgelegten Distanz. Verschiebungen, die weniger als eine Sekunde auseinanderliegen, zählen in dieselbe Session. Das Fenster ist auf fünf Sekunden begrenzt. Google bewertet das 75. Perzentil der Besuche, getrennt nach Mobil und Desktop; einzelne Läufe dürfen also streuen. Gut ist ein Wert von 0,1 oder kleiner (web.dev (öffnet in neuem Tab)).

Bei Schriften läuft die Störung über den Font-Swap: Erst rendert der Browser den Text in der Systemschrift aus dem Fallback-Stack, dann tauscht er, sobald die Webfont geladen ist. In der Zeit zwischen beiden Zuständen ändert sich die Breite fast jedes Textlaufs, mit ihr die Umbrüche. Unsichtbarer Text hilft an dieser Stelle nicht weiter: Auch wer den Text erst gar nicht anzeigt, verlegt ihn mit den Metriken der Ersatzschrift, und der Sprung beim Laden bleibt. web.dev führt beide Varianten als CLS-Ursachen (Optimize CLS (öffnet in neuem Tab)).

Zählt nur, was im Moment des Verschiebens im Viewport liegt. Auf meiner Startseite vergrößerte der Font-Swap unter dem Falz die Dokumenthöhe um 32 Pixel über 111 Knoten: Sichtbar war davon nichts, der CLS-Beitrag war null. Wer am Wert arbeiten will, arbeitet am ersten Viewport.

Warum „CLS unter 0,1“ das falsche Ziel ist

Die Schwelle von 0,1 beurteilt einen Messwert. Das Ziel dieser Arbeit ist ein Font-Swap, der das Layout unverändert lässt. Ist das erreicht, ist der CLS-Beitrag der Schrift per Konstruktion nahe null, auf jeder Leitung und in jedem Lauf. Ein Wert, der nur deshalb unter der Schwelle liegt, weil die Messung warm lief, steht beim nächsten Kaltlauf wieder drüber.

Chrome empfiehlt für den reinen Metrikwert font-display: optional: Der Browser räumt der Schrift rund 100 Millisekunden Blockzeit ein, danach wird in diesem Besuch nie mehr getauscht (Best practices for fonts (öffnet in neuem Tab)). Auf einer langsamen Leitung erscheint die Zielschrift dann schlicht nie. Der Messwert schrumpft, weil es nichts mehr zu verschieben gibt, und die Seite hat ihren Auftritt verloren. Ich habe optional bewusst verworfen und die Fallback-Metrik angeglichen: swap behalten, den Sprung wegnehmen.

Der Ablauf in fünf Schritten

  1. Befund erheben

    Gedrosselte Kaltmessung der Zielseite: mobiler Viewport, Slow 4G, vierfache CPU-Verlangsamung, frischer Browser-Kontext. Der Chrome-Trace nennt im CLSCulprits-Befund die Elemente, die sich verschieben. Zeigt er auf Textblöcke nach dem ersten Paint, ist die Schrift beteiligt.

  2. Ursache benennen

    Welche Rolle schiebt: die Fließtextschrift oder die Überschriftenschrift? Beide getrennt prüfen, sie verhalten sich unterschiedlich. Auf meiner Startseite war es die Fließtextschrift; die Überschriften blieben wegen ihrer festen Zeilenhöhe fast ruhig.

  3. Fallback-Stack auf Realität prüfen

    Welche Familien lösen auf dem Zielsystem überhaupt auf? Mein Stack nannte zehn Namen, drei davon existierten. Wer nicht auflösbare Familien kalibriert, kalibriert Luft.

  4. Metrik angleichen

    size-adjust rechnen oder messend kalibrieren, dann ein eigenes Fallback-Face bauen, das die Breite der Zielschrift trägt. Der Rechenweg steht im Abschnitt weiter unten.

  5. Abnehmen

    Kaltmessung gegen einen Kontroll-Arm: dieselbe Methode wie beim Befund, einmal mit und einmal ohne den Fix. Vorher und nachher sind nur vergleichbar, wenn die Methode identisch bleibt.

Zu Schritt drei gehört eine Einschränkung, die auf dem eigenen Rechner tückisch ist: Ist die Zielschrift lokal installiert, löst der Familienname sofort auf, und die Messung beweist nichts über die ausgelieferte Datei. Auf meinem Rechner liegt Quicksand als Systemschrift, trotzdem zeigte der CSS-Name vor dem Load den generischen Fallback an, mit exakt derselben Textbreite wie eine frei erfundene Familie. Referenzläufe laden die ausgelieferte woff2 deshalb unter einem Privatnamen, am saubersten über die Font Loading API mit den eigenen Bytes.

Die Metrik angleichen: size-adjust und ein eigenes Fallback-Face

Der Hebel ist ein eigenes Fallback-Face: eine @font-face-Regel, die eine Systemschrift unter dem Namen der Zielschrift bereitstellt, mit korrigierter Breite. size-adjust skaliert alle Metriken eines Faces um einen Prozentsatz, also Glyphenbreiten und Baseline-Tabellen (MDN (öffnet in neuem Tab)). Für Arial gegen Quicksand sieht das so aus:

@font-face {
  font-family: 'Quicksand Fallback';
  src: local('Arial');
  size-adjust: 103.5%;
  font-weight: 300 700;
}

font-weight muss die volle Achsenspanne nennen, hier 300 700. Ohne sie greift das Face nur bei Gewicht 400. Jeder fette Textlauf fällt dann unkorrigiert auf den nächsten Stack-Eintrag zurück, und die Messung erwischt eine Mischung aus beiden Zuständen.

Woher der Prozentsatz kommt: Chrome dokumentiert size-adjust als Verhältnis der durchschnittlichen Zeichenbreiten von Ziel- und Ersatzschrift und warnt selbst vor der naiven Mittelung über alle Glyphen (Improved font fallbacks (öffnet in neuem Tab)). Ich rechne die Werte mit fonttools aus den Font-Tabellen (head, hhea, OS/2, hmtx) und nehme als Basis die Zeichenbreiten eines echten deutschen Textlaufs, weil genau die die Zeilenumbrüche bestimmen.

Berechnet mit fonttools aus den Font-Tabellen, Basis: Zeichenbreiten eines deutschen Textlaufs gegen Quicksand.
Fallback-Schriftsize-adjust
Arial 103,06 %
Roboto 104,46 %
Segoe UI 105,17 %
SF Pro Rounded 110,94 %

Die Werte liegen so eng beieinander, dass der gesweepte Kompromiss von 103,5 % bestätigt war. Die Kurve zwischen 103 % und 104,5 % ist flach, der exakte Wert ist unkritisch. Die Gegenprobe lädt beide Dateien unter Privatnamen und misst denselben Textlauf vor und nach dem Swap: Die Textlauf-Rechnung behielt eine Restabweichung von −0,51 %, die verbreitete Durchschnittsformel −60,54 %. Der Unterschied zwischen beiden Formeln steckt bei Systemschriften mit großem Zeichensatz und ist unten bei den Fallstricken ausgeführt.

ascent-override und descent-override (MDN (öffnet in neuem Tab)) passen die Zeilenhöhe des Fallbacks an. Sie wirken nur, wenn die Zeilenhöhe tatsächlich an den Font-Metriken hängt. Meine Fließtexte tragen eine unitless line-height, deshalb blieben die Overrides hier wirkungslos und size-adjust ist der einzige Hebel.

Wie viel eine Schriftdatei selbst wiegt, behandelt der Screendesign-Ratgeber in seinem Ladezeit-Abschnitt.

Fallstricke, die eine Messung wertlos machen

Diese fünf Fehler liefern Zahlen, die nichts über die Seite aussagen. Jeder von ihnen ist mir in dieser Messung selbst untergekommen, jeder sah auf den ersten Blick sauber aus.

  • Mit vollem Cache gemessen

    Ein Trace mit Reload zieht Schrift und Bundle aus dem Cache. Der Swap fällt trivial aus, der CLS geht gegen null, ohne dass die Seite besser wurde.

    • Erkennungsmerkmal: Der Kaltlauf weist „estimated wasted bytes“ aus, der warme Lauf nicht.
    • Kalt geht nur über einen frischen, isolierten Browser-Kontext in jedem Lauf.
  • Der Kontroll-Arm, der nichts bewirkt

    Eine Vergleichsvariante, deren Schrift gar nicht auflöst, sieht aus wie ein bestandener Test. Ein benannter Fallback, den es auf dem System nicht gibt, misst denselben Zustand wie eine frei erfundene Familie: auf meiner Startseite 250,81 px Textbreite in beiden Fällen, bei 412 px Viewport.

    • Kontroll-Arm auf generische Keywords stellen: monospace, serif.
    • Ein Wächter bricht ab, wenn der Patch nicht in jedem gepatchten Lauf greift.
  • Die Durchschnittsformel für size-adjust

    Der ungewichtete Mittelwert über alle Glyphen liefert bei Systemschriften grob falsche Werte: 44,01 %, gerechnet wären 110,94 %, Faktor 2,5 daneben. Die Systemschrift bringt rund 1600 Glyphen mit, viele davon breite Symbole; die Zielschrift deckt nur Latin ab.

    • Rechnen über die Zeichenbreiten eines echten Textlaufs: genau die bestimmen die Zeilenumbrüche und damit den Shift.
    • Gegenprobe im Browser: textbasiert blieb eine Restabweichung von −0,51 %, die Durchschnittsformel −60,54 %.
  • Varianten in einer Seitensitzung

    Sequenzielle Messungen in einer Sitzung kontaminieren einander. Derselbe size-adjust-Wert erschien im Sweep mit 15 px Versatz, im Einzellauf mit 3,5 px.

    • Plateau per Sweep suchen, die belastbare Zahl aus einem Einzellauf gegen frischen Zustand holen.
  • Das @font-face lädt asynchron, auch bei src: local()

    Ohne await document.fonts.load() misst der erste Durchlauf das Layout der vorherigen Variante. Ein Sweep gab so ein Optimum von 103,25 % aus, korrekt waren 101,3 %.

    • Vor jedem Messlauf document.fonts.load() abwarten, sonst verschiebt sich die ganze Tabelle um eine Zeile.

Die Abnahme gegen den Kontroll-Arm

Abnahme heißt hier: dieselbe Methode wie beim Befund, einmal mit und einmal ohne den Fix, und ein Kontroll-Arm, der belegt, dass die Messung überhaupt auf Schriftmetriken reagiert. Auf meiner Startseite sah das so aus:

Vorher und nachher, unter derselben Drosselung

Kurz gesagt: Vorher verschob der Font-Swap Text um bis zu 31,5 Pixel und trieb den CLS im Trace-Kaltlauf auf 0,1069, nachher zeigt dieselbe Methode gerundet 0,00.

  • Verbesserungswürdig: Layout Shift vor dem Fix

    0,1069

    Mobil gedrosselt (Slow 4G, vierfache CPU-Verlangsamung), Kaltlauf. Drei Läufe, Median 0,1069, Spanne 0,1063 bis 0,1069. Die Gut-Schwelle liegt bei 0,1.

  • Gut: Layout Shift nach dem Fix

    0,0016

    Dieselbe Drosselung, Median aus fünf Kaltläufen mit PerformanceObserver. Der Trace-Kaltlauf zeigt gerundet 0,00.

  • Gut: Größter Versatz im ersten Viewport

    3,2 px

    Vorher 31,5 px, gemessen über fünf Seiten gegen Arial und Roboto.

  • Gut: Textlauf-Sprung beim Font-Swap

    1,8 %

    Vorher 12,0 %: derselbe Textlauf vor und nach dem Font-Load, Viewport 412 px breit.

Alle Messwerte im Detail
CLS- und LCP-Zeilen: mobil gedrosselt (Slow 4G, vierfache CPU-Verlangsamung), Kaltläufe im isolierten Browser-Kontext. Versatz- und Textlauf-Zeilen: lokale Messreihen, Bedingung je Kachelnote.
Merkmalvorhernachher
Cumulative Layout Shift (Trace-Kaltlauf) 0,1069 0,00
Cumulative Layout Shift (Observer, 5 Kaltläufe) nicht gemessen 0,0016
Größter Versatz im ersten Viewport 31,5 px 3,2 px
Textlauf-Sprung beim Swap 12,0 % 1,8 %
Largest Contentful Paint 3,4 s 2,7 s

Der Sprung von 0,1069 auf 0,0016 ist das Gesamtergebnis zweier Stufen: Der Font-Stack wurde von zehn Einträgen auf lösbare Familien getrimmt, und das Fallback-Face kam dazu. Wie viel das Face im bereits getrimmten Zustand noch beiträgt, zeigt der Arm ohne Face: 0,0155 gegenüber 0,0016 mit Face. Den ungetrimmten Zustand habe ich bewusst nicht rekonstruiert, denn Raten wäre hier genau die Fehlerquelle, die dieser Ratgeber beschreibt. Den isolierten Anteil des Stack-Trims gibt es deshalb als eigene Zahl nicht.

Die Kalibrierung zeigt derselbe Bericht: Selbst der gröbste Metrikbruch, der Kalibrierungslauf mit monospace als Ersatzschrift, bringt die getrimmte Seite nur auf 0,0148. Der Body-Swap ist danach kein nennenswerter CLS-Treiber mehr, egal wie weit eine Fallback-Metrik danebenliegt.

Bestanden ist die Abnahme, wenn der Swap das Layout unverändert lässt: Der Textlauf-Sprung fällt von 12,0 % auf 1,8 %, der größte Versatz im ersten Viewport von 31,5 auf 3,2 Pixel. Der CLS-Wert ist dann die Folge, und er fällt so weit unter die Schwelle, dass sie als Kriterium langweilig wird.

Mit einem LLM messen: Wächter statt Vertrauen

Diese Prüfung fahre ich zusammen mit einem LLM. Es baut die Messskripte, liest Font-Tabellen mit fonttools, rechnet size-adjust in beiden Maßen und misst Variantenreihen durch. Die Gegenrechnung der Zahlen, für die ich als Mensch Stunden bräuchte, erledigt es in Minuten. Genau diese Stärke ist auch das Risiko: Jeder der fünf Fallstricke oben ist ein Fehler, den ein LLM mit plausibler Ausgabe und ohne jede Fehlermeldung produziert hat. Die warmen Traces meldeten CLS 0,00 und hätten die Abnahme belegt. Der Sweep mit dem ungewarteten @font-face wies ein falsches Optimum aus. Die Tabelle sah trotzdem sauber aus. Der Kontroll-Arm mit einer Systemschrift, deren Name nicht auflöst, maß zweimal denselben Zustand und sah aus wie ein bestandener Test.

Die Arbeitsregel daraus: Jede Messung braucht einen eingebauten Wächter, der scheitert, wenn die Messung nichts misst. Der Kontroll-Arm läuft auf generische Keywords (monospace, serif), damit er garantiert anders misst als der Zielzustand. Ein Abbruch beendet jeden Lauf, in dem der CSS-Patch des Zielzustands nicht greift; sonst misst du still zweimal dasselbe. Und jede Zahl rechnet das LLM ein zweites Mal gegen, auf einem unabhängigen Weg. Ein Ergebnis ohne Kontroll-Arm ist kein Ergebnis.

Der Kickoff-Prompt zum Mitnehmen

Der komplette Messaufbau steckt als direktiver Auftrag in einer Textdatei: Messaufbau mit mobilem Viewport, Slow 4G, vierfacher CPU-Drossel, frischem Kontext je Lauf und fünf Läufen mit Median und Spannweite; erzwungener Kaltlauf samt Erkennungsmerkmal; Kontroll-Arm mit Wächter; Rechnung über einen echten Textlauf; eine scharfe Abnahmedefinition. Du übergibst die Datei an Claude Code oder ein anderes agentisches Werkzeug mit Browser-Zugriff, nennst deine URL und lässt laufen.

Der Kickoff-Prompt als Textdatei liegt hier, 7,8 KB.

Font-CLS prüfen lassen

Ich baue den Messaufbau mit Wächtern, fahre die Kaltläufe und gleiche die Fallback-Metrik an. Vorher und nachher aus derselben Methode, für Agenturen auch als White-Label.

Zur Agentur-Kooperation

Häufige Fragen

  • Warum springt meine Website beim Laden?

    Oft steckt eine nachgeladene Schrift dahinter. Der Browser zeigt deinen Text zuerst in einer Ersatzschrift und tauscht sie aus, sobald die eingebundene Datei da ist. Laufen die beiden unterschiedlich breit, brechen alle Zeilen neu um, und alles darunter rückt mit. Google misst das als Cumulative Layout Shift, kurz CLS. Gut ist 0,1 oder kleiner. Der Sprung verschwindet, ohne dass du die Schrift aufgibst: Die Ersatzschrift lässt sich auf die Breite der Zielschrift trimmen.

  • Muss ich font-display: swap abschalten, wenn der Text springt?

    Nein. Swap zeigt Text sofort und tauscht die Schrift beim Nachladen aus, der Sprung ist der Preis dafür. Unsichtbarer Text bis zur fertigen Datei wäre schlechter: Besuchende sehen so lange nichts. Der Hebel liegt am Fallback: size-adjust gleicht die Ersatzschrift an die Zielschrift an, am saubersten über ein eigenes Fallback-Face. Auf meiner Startseite blieb danach eine Restabweichung von −0,51 %.

  • Reicht PageSpeed Insights, um Layout Shift zu messen?

    Als ersten Eindruck ja, für die Diagnose nein. Den Befund fahre ich im Chrome-Trace, und der muss kalt laufen. Ein Reload aus dem Cache ließ den Swap bei mir trivial ausfallen, der Trace wies CLS 0,00 aus, ohne dass die Seite besser geworden war. Erst ein frischer Browser-Kontext zeigt den Sprung, den Besuchende beim ersten Laden sehen. Im CLSCulprits-Befund des Traces stehen dann die Elemente, die schieben.

  • Warum zeigt jede CLS-Messung einen anderen Wert?

    CLS summiert die Verschiebungen einer Sitzung, und jede Sitzung verläuft anders. Liegen zwei Sprünge weniger als eine Sekunde auseinander, zählen sie gemeinsam, das Fenster ist auf fünf Sekunden begrenzt. Cache, Netzwerk und Timing entscheiden, was hineinfällt. Deshalb zeigt jeder Lauf einen anderen Wert, und Google bewertet das 75. Perzentil der Besuche, getrennt nach Mobil und Desktop. Vergleichen lässt sich nur, was mit identischer Methode gemessen wurde. In meiner Abnahme liefen Vorher und Nachher als je ein Kaltlauf unter derselben Drosselung.

Weiterführende Informationen

  • Glossar

    Cumulative Layout Shift und Core Web Vitals: beide Fachbegriffe kompakt erklärt.

  • Screendesign und Ladezeit

    Wie Gestaltungsentscheidungen Payload treiben, im Ladezeit-Abschnitt des Ratgebers.

Durchsucht alle Seiten, das FAQ und das Glossar. Mindestens 3 Zeichen.