Performance: Cumulative Layout Shift (CLS) für Web Vitals optimieren

Ruhigerer Seitenaufbau: Wie wir bei heise online unseren CLS-Wert optimiert und damit eine dauerhafte Verbesserung der UX herbeigeführt haben.

In Pocket speichern vorlesen Druckansicht 34 Kommentare lesen
Lesezeit: 9 Min.
Inhaltsverzeichnis

Ruhigerer Seitenaufbau: Wie wir bei heise online unseren CLS-Wert optimiert und damit eine dauerhafte Verbesserung der UX herbeigeführt haben.

Die sogenannten (Core) Web Vitals sind drei Performance-Kennzahlen, die Google als besonders wichtig für die Einschätzung der generellen Performance beziehungsweise User Experience einer Website ansieht. Diese drei Werte sind Largest Contentful Paint (LCP), First Input Delay (FID) und Cumulative Layout Shift (CLS). Bei heise online haben wir vor allem ein Defizit beim CLS festgestellt und uns daraufhin entschlossen, diesen zu verbessern.

Die Web Vitals können wir bereits in den gängigen Performance-Tools sehen. So werden diese in Googles eigenen Tools wie den PageSpeed Insights, Lighthouse und dem CrUX-Dashboard angezeigt, aber auch im Open-Source-Tool WebPagetest. Darüber hinaus hat Addy Osmani eine Chrome-Extension herausgebracht, die die Web-Vitals-Kennzahlen für die aktuell aufgerufene Seite anzeigt.

Wer gerne in eigenen Analyse-Tools die Werte bei Seitenaufrufen der eigenen User (also Real User Monitoring – kurz RUM-Data) protokollieren möchte, kann dafür auf eine kleine JavaScript-Bibliothek von Google zurückgreifen.

Mehr Infos

CrUX

Dieses Acronym steht für Chrome User Experience. Wer Googles Chrome Browser verwendet und der Statistiksammlung nicht widerspricht, stellt automatisch Daten für den CrUX-Report zur Verfügung. Diese Daten finden sich aufbereitet in Tools wie PageSpeed Insights oder dem CrUX-Dashboard wieder. Die Daten sind öffentlich und stehen auch via API bereit.

Mit Googles CrUX-Daten (siehe Kasten) können wir uns auch historische Daten anschauen und so die Entwicklung der eigenen Performance sehen. Dies hilft, um im Nachhinein noch festzustellen, welche Änderung auf der Seite zu einer Verschlechterung bestimmter Kennzahlen geführt hat, oder um zu überwachen, dass eine vorgenommene Verbesserung nicht schleichend wieder verloren geht.

Der CLS-Wert ist schlecht, wenn sich laufend noch Elemente auf der Seite verschieben, während diese geladen wird oder sogar danach noch. In die Berechnung des Werts fließen die Größe des Elements sowie die Verschiebung an sich mit ein. Ein Klassiker für eine Layout-Verschiebung ist Werbung, aber auch nachladende Schriften. Langsam ladende Ressourcen wie auch spät zur Seite hinzugefügtes CSS (beispielsweise erst durch JavaScript eingefügt) können hier ebenfalls problematisch sein.

Im Falle von heise online waren es vor allem Werbung und Bilder. Für die Startseite ergaben sich aus den CrUX-Daten der letzten vier Wochen ("Felddaten"), dass gerade einmal 44 Prozent eine gute Erfahrung hatten (Wert < 0,1), 25 Prozent hatten verbesserungswürdige Erfahrungen (Wert 0,1 bis 0,25) und 31 Prozent hatten sogar eine schlechte Erfahrung (Wert > 0,25).

Um die Verursacher des Layout Shifts ausfindig zu machen, haben wir mit den Chrome Developer Tools einen Performance-Test-Durchlauf mit langsamer Verbindung vorgenommen ("Fast 3G"). Reines Beobachten beim Seitenladen lässt bereits große Verschiebungen sehr deutlich erkennen. Ist im Performance-Tab der Haken bei "Screenshots" gesetzt, wird auf der Ergebnisseite ein Filmstrip angezeigt. Mit dessen Hilfe lässt sich nachvollziehen, wenn sich Elemente gleich mehrfach bewegt haben.

"Layout Shift Regions" in den Chrome Developer Tools aktivieren.

Darüber hinaus gibt es inzwischen eine Möglichkeit, sich verschiebende Elemente deutlich markieren lassen zu können – besonders hilfreich bei kleinen Verschiebungen, die für das Auge nicht so ersichtlich sind und um zu erkennen, wie viel des DOMs eigentlich betroffen ist. In den Developer-Tools drückt man dafür Esc, im daraufhin aufgeklappten Menü klickt man oben links auf die drei Punkte und wählt dort "Rendering" an. Im Tab Rendering lässt sich nun "Layout Shift Regions" durch Setzen des Hakens einschalten. Beim nächsten Reload werden dann eingefärbte Quadrate auf der Seite angezeigt, wo Bereiche bewegt wurden.

Sind einzelne Elemente ausfindig gemacht, kann man mit den üblichen Developer-Tools die Gründe für die Verschiebung herausfinden und diese aus dem Weg schaffen. Manchmal lässt sich das Problem aber nur verbessern und nicht gänzlich aus der Welt schaffen.

Bereiche Leaderboard und Top-Teaser auf der heise online Startseite.

Unsere zwei Hauptprobleme waren die Werbung über dem Hauptseiteninhalt und die Bilder im Top-Teaser auf der Startseite. Theoretisch startete die Website direkt oben unter der Navigationsleiste, wenn keine Leaderboard-Werbeposition ausgegeben wurde – allerdings wird auf dieser Position meistens eine Werbung ausgegeben. An dieser Stelle haben wir mehrere leere HTML-Tags mit 0 Pixel Höhe liegen für verschiedene Werbe-Größen.

Eigentlich sollte nur das eine Tag auf die richtige Größe gezogen werden, für das es auch eine Werbung gab. Durch die Analyse stellten wir aber fest, dass die Seite dreimal sprang. Einmal circa auf 90 oder 300 Pixel Höhe, dann nochmal auf etwa 180 respektive 390 Pixel und wieder zurück auf 90/300 Pixel. Längere Analyse unseres Codes brachte eine kleine, Sekundenbruchteile dauernde Fehlfunktion ans Licht, wo ein zweiter Container eine Höhe zugewiesen bekam und direkt danach dann aber – wie alle nicht befüllten Werbe-Positionen – aus dem DOM entfernt wurde. Daher der doppelte Sprung, obwohl nur eine Werbeposition angezeigt wurde. Als das aus der Welt war, wurde es einfacher. Eine Anfrage bei unseren Kolleg*innen, die sich um die Online-Werbung kümmern, brachte die Information, welches Werbe-Format am häufigsten ausgespielt wird – es war das mit 90 Pixel Höhe. Also trugen wir für einen Container, der alle Werbe-Positionen umspannt, eine min-height: 90px ein und schon war ein Großteil der Seite viel ruhiger.

Aber das war erst die halbe Miete. Der große Seitencontainer verschob sich nun zwar nur noch, wenn eine Werbung mit 300 Pixeln Höhe ausgespielt wurde, aber der Inhalt der Seite selbst war noch nicht optimiert.
Die Startseite von heise online beginnt mit mal mehr, mal weniger Reihen von Artikel-Teasern, wir nennen diesen Bereich Top-Teaser. In den Top-Teasern sind unterschiedlich große Bilder, je nach Menge an Teasern in einer Reihe. Wie für viele andere Bilder bei heise online setzen wir dafür unser eigenes Custom Element <a-img> ein, dieses berechnet per JavaScript die richtige Bildgröße anhand des zur Verfügung stehenden Platzes und kümmert sich um größere Bilder bei höheren DPIs des individuellen Anzeigegeräts eines Users. Außerdem bewerkstelligt es das Lazy-Loading, sodass Bilder, zu denen ein User nie hinscrollt, auch gar nicht erst geladen werden. (In einem früheren Blog-Beitrag haben wir <a-img> einmal im Detail vorgestellt: Lazy Loading Images mit Custom Elements.)

Dadurch dass die Bilder erst durch JavaScript in die Seite eingefügt werden, "sieht" der Browser diese auch erst dann und kann sie nicht vorher anfangen zu laden. Es ergibt sich also die Lade-Reihenfolge: HTML-Dokument, JavaScript, Bilder. Auch führt erst das JavaScript dazu, dass der korrekte Platz des Bildes reserviert wird, weshalb sich ein Layout-Sprung ergibt, wenn der Browser das JavaScript verarbeitet. Bei Bildern außerhalb des First-View kein Problem. Die Lösung war hier im Prinzip sehr simpel, wir stellten für die Top-Teaser wieder auf <img>-Tags mit einfachem srcset-Attribut (siehe MDN) um und nutzten den padding-top: 56.25%-Trick, um Platz für das Bild zu reservieren. (In Zukunft wird das übrigens einfacher, wenn die CSS Property aspect-ratio weiter verbreitet sein wird.)

Des Weiteren fügten wir noch ein wenig handverlesenes Critical CSS im <head> ein. Eine Werbeposition in den Top-Teasern gibt es nur auf Mobilgeräten, diese blenden wir daher bei Desktop-Auflösungen von vornherein aus, ohne die Erkenntnis des JavaScripts mit dem selben Ergebnis abzuwarten. Einen ähnlichen Effekt hatten wir bei einem Custom Element in der Navigationsleiste, hier haben wir mit CSS eine Definition des JavaScripts vorgegriffen.

Selbstverständlich ist bei solchen Eingriffen Vorsicht geboten! Prinzipiell sollen die Custom Elements gekapselte Komponenten sein, in die nicht von außen eingegriffen wird. Hier fiel die Abwägung allerdings zugunsten des ruhigeren Seitenaufbaus aus.

Nach diesen Maßnahmen hatte sich unser CLS-Wert drastisch verbessert und war dauerhaft in einem Bereich unter 0,0 – jedenfalls für uns. Nach dem Rollout behielten wir die CrUX-Daten im Auge und sie verbesserten sich stetig für unsere User. Zum aktuellen Zeitpunkt liegen sie (für Desktop-User) bei 85 Prozent gut (vormals 44 %), 12 Prozent verbesserungswürdig (vormals 25 %) und nur noch 3 Prozent schlecht (vormals 31 %).

Durch diese Optimierung haben wir zwar einerseits den CLS-Wert der Web Vitals verbessert, welche eventuell später mal einen Teilfaktor im Bereich des Rankings auf der Suchergebnisseite bei Google ausmachen werden, aber wir haben vor allem die User Experience verbessert. Besonders dürfte das für User gelten, die unsere Seite nach wie vor mit einer Ad-Blocker-Ausnahme besuchen und uns damit unterstützen (vielen Dank an dieser Stelle).

Wie so häufig, wenn wir hier von unserer Arbeit berichten, stellt dieser Text keinen Schlusspunkt für einen bestimmten Entwicklungsbereich dar. Wer sich unsere PageSpeed-Insights-Ergebnisse angesehen hat, wird bemerkt haben, dass wir uns bei der Performance (und damit in Googles Web-Vitals-Sinne auch bei der User Experience) noch auf einem Weg befinden, aber die Optimierung des CLS war hier immerhin schon mal eine erste gute Etappe. (hih)