N. Z.

Web Core Vitals optimieren - Praxisbeispiel

Geschrieben von Nico Zorn veröffentlich am in der Kategorie UX

In meinem ersten Beitrag zu Web Core Vitals habe ich diese bereits vorgestellt. Es geht bei ihnen darum, das Nutzererlebnis zu verbessern, durch objektiv messbare Dinge wie verbesserter Ladezeit und ein Nicht-Verrutschen bzw. die Konsistenz angezeigter Elemente. Im Folgenden will ich praktisch darstellen, wie eine Optimierung ablaufen kann.

Der Ausgangspunkt

Struktur der Seite via wirify: Logo und Navigation, Breadcrumb, H1, Titelbild, Fließtext. Zu Beginn steht eine einzelne Website (URL), die zwar nicht ganz vernachlässigt ist, aber dennoch im unteren gelben Bereich von Googles Test-Tools rankt. Als Optimierungen in diesem Bereich wurde bereits durchgeführt:

  • LazyLoading für alle Bilder
  • Optimierung der Bilddimensionen
  • GZip-Komprimierung

Dies führt aber nicht dazu, dass alle Werte optimal sind. Besonders auffällig war ein CLS (Cumulative Layout Shift) von 0.5. Als gut gelten hier Werte unter 0.1; alles über 0.2 gilt als schlecht.

Dieser CLS (korrekter eigentlich Layout Shift Score) ist das Produkt des Anteils der sich verschiebenden Pixel (impact fraction) und der Distanz, um die sich ein Element verschiebt (distance fraction), beides bezogen auf die größte sichtbare Dimension, hier die Display-Höhe bzw. -Breite.
Konkretes Beispiel: Verschiebt sich ein Bild, das 50% des Bildschirms einnimmt (0.5 impact) um 80% des Bildschirms nach unten (0.8 distance), ergibt das einen CLS von 0.5*0.8=0.4.

Das bedeutet: Etwa die Hälfte aller Pixel werden nach dem Laden verschoben. LazyLoading, das Bilder zunächst komplett wegblendet, hilft bei Bildern "above the fold" („über der Falz“), also im unmittelbar ohne Scrollen sichtbaren Bereich, gerade nicht. Manche Tools erkennen direkt, dass das Bild im Viewport ist und laden es – effektiv so, als gäbe es kein LazyLoading. Andere Implementationen führen genau zu dem problematischen Ausblenden und späteren Nachladen, das einen plötzlichen Sprung verursacht.

Ein weiteres bekanntes Problem sind Werbeeinblendungen, die über Werbenetzwerke ausgespielt sind und teils massiv das Laden blockieren. Google schlägt auch einige weitere Optimierungen vor.

Es ist klar, dass diese Probleme zentral sind. Ihre Behebung könnte Folgeprobleme direkt abmildern. Einige Vorschläge aus den Tools haben hingegen eher großen Aufwand und vermutlich eher kleinen Nutzen. Wichtig ist erst einmal, irgendwo anzufangen – und diese Probleme sind ein guter Einstiegspunkt.

Eines sollte man dabei nicht vergessen: Es macht einen großen Unterschied, ob man eine handgeklöppelte, einzelne HTML-Seite ohne Abhängigkeiten optimiert oder ein komplexes Content-Management-System (CMS), bei dem viele Teile ineinandergreifen. Einzelne HTML-Seiten bieten den Vorteil, dass man ohne Rücksicht auf anderes werkeln kann, sind aber in der Skalierbarkeit eingeschränkt. Bei einem CMS muss man hingegen Interdependenzen beachten, kann dafür aber meist alle gleich aufgebaute Seiten (Templates, z. B. Kategorieseite, Produktseite, Blogbeitrag) auf einmal optimieren. Im konkreten Beispiel war die Seite Teil eines CMS, eine Kategorieseite.


Meine Test-Tools

Es gibt zahlreiche Tools und letztlich muss man hier wählen, was für einen gut funktioniert – vielleicht mit einem Auge auf Google, da ja Google letztlich die Seite „abnimmt“. Für die grundsätzliche Optimierung nutze ich daher folgende kostenlose Tools:

Bei größeren Seiten nutze ich u. U. Screaming Frog oder andere Tools – allerdings nur zur späteren Überprüfung. Denn auch hier beginnt die Optimierung bei einer Einzelseite und wird dann auf Template und Website skaliert. Der spätere Test bestätigt mir nur, ob die Maßnahmen auch in der Breite ausreichend greifen oder sagen mir, dass ich noch nachkorrigieren muss.

Maßnahme 1: Rechenintensive Scripte verbessern

Nun zur Optimierung. Als erstes habe ich mir die Werbeanzeigen vorgenommen, die auf dieser Seite ausgespielt werden. Dies auch, weil sie auf jeder Seite vorhanden sind, nicht nur auf diesem Typ. Eine Optimierung an dieser Stelle optimiert also gleich die gesamte Website.

Im konkreten Fall ist das betreffende Werbenetzwerk AdSense, das Netzwerk von Google. Von wem ein langsam ausgespielter Inhalt stammt, spielt jedoch keine Rolle: Es gibt keinen Bonus für Google-Dienste. Denn dem User ist es letztlich egal, wer im Hintergrund lange Ladezeiten verursacht; am Ende bleibt das lange Warten auf eine Seite. Das Problem müssen auch nicht immer Werbebanner sein; große Libraries wie jQuery oder einige Scripts sorgen ebenfalls für hohe Rechenlast. Rechenlast, nicht Dateigröße, denn ein Blick auf die Dateigröße genügt nicht: Auch die Ausführungszeit des Scripts ist wichtig!

Im konkreten Fall kam mir entgegen, dass die Werbung eigentlich niemand braucht. Zugegeben: Sie finanziert die Seite, aber niemand beschwert sich, wenn sie nicht sofort da ist. Außerdem befindet sie sich weiter unten auf der Seite sowie am Ende der rechten Spalte und blockiert damit auch nichts darunter. Dass sie nicht above the fold unmittelbar geladen werden muss, erleichtert die Umsetzung deutlich.

Die Lösung war, das Laden der erst später benötigten Funktionalität zu verzögern. 3 bis 5 Sekunden haben sich nach mehreren Tests als guter Wert gezeigt. Die Flächen, in die die Werbung geladen wird, sind dabei speziell ausgezeichnet und werden entsprechend vorgehalten. Sollte ein Nutzer sie doch sehen, sind sie einfach leer. (Bonus-Tip für Werbetreiber: Kleines Platzhalter-Bild oder Text einblenden, der zum Beispiel diesen Werbeplatz vermarktet. Hilft evtl. auch gegen Ad-Blocker. Und natürlich messen, ob und wie sich Impressionen, Klicks und Einnahmen durch die Maßnahmen verändern.)

Man mag jetzt denken, eine Zeitverzögerung sei Schummeln und das Tool erkennt sie nur nicht mehr. Das ist aber egal: Es geht hierbei vor allem um den First Contentful Paint, also die erste Darstellung einer Seite. Elemente, die hier so oder so nicht angezeigt werden, können problemlos später geladen werden. Sie sollten es sogar, denn man sieht sie zu Beginn nicht; sie sind zu diesem Zeitpunkt unnötig geladen. Was zählt ist die Wahrnehmung des Users.

Ein Knackpunkt kann sein, dass eine bestimmte Funktion eben doch notwendig ist und die Darstellung beeinflusst. Dies muss man im Einzelfall prüfen. Gerade im Bereich JavaScript werden einige Libraries ohne rechtes Nachdenken verwendet. Übrigens nutzt auch die Beispielseite jQuery und man könnte hier vermutlich optimieren. Aus Bequemlichkeit und weil der Aufwand deutlich größer wäre als anderes, habe ich (zumindest derzeit) darauf verzichtet.

Analog wie mit Werbebannern kann man mit anderen rechenintensiven Elementen vorgehen, typisch sind:

  • Videos, insbesondere YouTube- und Vimeo-iFrames;
  • Werbenetzwerke;
  • Social Sharing Buttons und Widgets;
  • Chatfunktionen;
  • einige Kommentarsysteme (z. B. Disqus);
  • 3rd-Party-Scripts, -Libraries und JavaScript allgemein.

Gerade viele Scripts und rechenintensive, aber kaum genutzte, Libraries summieren sich schnell auf. Lösungen gibt es mehrere, unter anderem LazyLoading oder eine 2-Klick-Lösung, die z. B. Videos und APIs nur dann nachlädt, wenn der Nutzer durch Klick auf ein Vorschaubild klar signalisiert, dass er das Video anschauen möchte.

Maßnahme 2: Titelbild verschiebt den Inhalt

Bilder sind nach wie vor eine der gewichtigsten Gründe für überladene Seiten. Im Beispiel wurde schon gut vorgearbeitet: Bilder werden mit LazyLoading geladen (also erst kurz bevor sie tatsächlich sichtbar werden) und in etwa in passenden Größen vorgehalten. „In etwa“ weil es auch hier einen Kompromiss gibt und nicht wirklich jede Abmessung vorhanden ist – wenn ein Bild von 200x200 Pixeln auf 190x190 Pixel herunterskaliert wird, könnte man vielleicht 3KB sparen. Das lohnt den Aufwand nicht. Bessere Bildformate habe ich mir allerdings vorgemerkt, denn dies könnte man systematisch für alle Bilder durchführen.

Das aktuelle Hauptproblem beim Titelbild ist aber ohnehin nicht die Dateigröße – diese ist nur Auslöser. Denn ein Bild lädt immer langsamer als einfacher Text. Deshalb wird der Text unter dem Bild auch vor diesem angezeigt: das Bild schiebt sich dann dazwischen. Die Lösung ist an sich simpel: Das Bild muss mit Höhe und Breite ausgezeichnet werden. So hält der Browser diese Fläche für das Bild frei, der Text erscheint unter einer zunächst leeren Fläche. Simpel – in der Theorie.

Denn wir haben uns an Best Practices gehalten, Quellcode, Inhalt und Design getrennt. Größenanweisungen finden sich in einer zentralen CSS-Datei – auch Größenangaben für das Bild. Das funktioniert aber nicht, denn auch die muss der Browser erst verarbeiten. Bis das geschieht, weiß er nicht, dass das Bild mehr Platz benötigt.

Die Anweisungen für das Bild müssen also priorisiert geladen werden. Das geht nur, wenn wir sie direkt in den Quelltext der Seite einbauen: Direkt ans Bildelement oder in einem <style> … </style>-Abschnitt, noch besser sogar in den <head> der Seite, so dass sie unmittelbar beim Aufruf geladen werden. Hier definieren wir ggf. auch Varianten für Auflösungen.

Für die Beispielseite musste ich eine zusätzliche Schwierigkeit lösen. Individuell könnte ich für die Seite eindeutige Dimensionen vorgeben. Auf weiteren Seiten der gleichen Art existierten allerdings deutlich unterschiedliche Formate als Titelbild; sowohl hoch als auch quer und mit diversen Abmessungen. Eine Vereinheitlichung wäre ein Ansatz, hier aber unpraktikabel. Meine Lösung war eine automatische Berechnung der Bildabmessungen und der aspect ratio. Das bedeutet, dass der Servercode die Bilddatei untersucht und passende Maße in das img-Tag einträgt. Das ist keine perfekte Lösung, funktioniert aber.

Identisch können wir auch für weitere Elemente vorgehen, die sich above the fold befinden. Ich habe den Code übrigens zusätzlich in der (später geladenen) CSS-Datei gelassen. Das ist zwar doppelt, aber so bleiben alle Anweisungen auch an einem zentralen Platz. Wermutstropfen: Der Pflegeaufwand ist höher und ist man inkonsequent, entsteht leicht Chaos. Insbesondere muss man vorsichtig sein, falls man Attribute in den Elementen nutzt, die durch die CSS-Datei überschrieben werden sollen (=>!important nutzen).

Resultat dieser Maßnahme: Das Bild nimmt nun auch vor dem Laden den korrekten Platz ein, die CLS konnte auf 0 gebracht werden, der User leidet nicht mehr unter plötzlichem Springen/Ruckeln. Dies wird analog auch für ähnliche Elemente umgesetzt.

Maßnahme 3: Bilder als webP bereitstellen ("Moderne Bildformate")

Bilder sind, wie gesagt, oft die größten Elemente auf der Seite. Text vergrößert eine Datei hingegen kaum. Bilder waren auf dieser Seite schon recht optimiert, allerdings nur mit klassischen Formaten. Tools weisen meist darauf hin, dass moderne Formate genutzt werden sollten. Bilder haben hier zudem den Vorteil, dass eine Bilddatei für sich steht, also von nichts anderem abhängt oder anderes beeinflusst. Das war Grund genug, zu schauen, was sich hier noch sparen lässt.

Als ersten Schritt wandelte ich einige Bilder in webP um und nutzten diverse Tools aus dem Web. Das Ergebnis mit den Voreinstellungen war ernüchternd:

  • Bilder, die durch die "Optimierung" größer wurden;
  • "Verlustfreie" Bilder, bei denen ganz klar Farben fehlten.

Auch manuelle Einstellungen verbesserten das Ergebnis nicht unbedingt. Und während ich Bilder nicht Pixel für Pixel untersuche, sollten das Aussehen doch nicht deutlich leiden. Letztlich griff ich auf Googles WebP-Converter zurück und schrieb mir ein Batch-Script zur Massenumwandlung von Bildern. Dieses Ergebnis war gut: ein Abgleich durch die eigenen Augen zeigte kaum sichtbare Veränderungen und die Dateigröße schrumpfte. Je nach Bild war dies marginal oder deutlich über 50%.

Mit der Umwandlung sind die Bilder aber noch nicht eingebunden und dies kann je nach CMS sehr trickreich sein. Denn das CMS muss irgendwie wissen, dass das betreffende Bild auch als webP vorliegt. Im konkreten Fall habe ich die webP-Dateien identisch zu den vorherigen Dateien benannt, prüfe, ob die jeweilige Datei existiert und binde sie dann ein.

Grundsätzlich bietet sich hier das <picture>-Element an: Es kann mehrere Bildvarianten bereitstellen, sowohl für verschiedene Auflösungen als auch in verschiedenen Formaten. Der Browser wählt dann das jeweils passende Bild in einem unterstützten Format an. Das sieht dann beispielsweise so aus:

<picture>

<source src="dateiname.webp" type="image/webp" />

<source src="dateiname.jpg" type="image/jpeg" />

<img src="dateiname.jpg" alt="alt-text" />

</picture>

 

In dieser Basisdarstellung fehlen noch die Auszeichnung mit LazyLoading und die mitgegebene Breite/Höhe wie in Maßnahme 2. Für hochauflösende Retina-Displays kann man zudem größere Varianten bereitstellen. Das Prinzip lässt sich auf alle Bilder anwenden.

Andere Empfehlungen

Ich habe oben drei Maßnahmen ausführlich beschrieben. Googles Tools geben zahlreiche weitere Empfehlungen, die jedoch im Einzelfall zu prüfen sind. Für mich funktioniert dabei ein schnelles Vorgehen: Schnell auf einer Einzelseite ausprobieren, prüfen, ob es etwas bringt, ggf. verwerfen und zur nächsten Idee übergehen. Oben ist es mehrfach angeklungen: Oft ist dies auch eine Aufwandsentscheidung, mitunter auch ein Kompromiss mit anderen Erwägungen.

Was habe ich zum Beispiel verworfen oder zurückgestellt?

  • Reduzierung der Server-Response-Time: Diese Website läuft auf einem mit anderen Websites geteilten Server. Schneller geht fast immer, kostet aber auch mehr – und ist es hier nicht wert.
  • http/2: Dies würde Multiplexing erlauben, die gleichzeitige Anfrage mehrere Ressourcen (Dateien) über eine Verbindung. Ohne http/2 muss jeweils eine neue Verbindung pro Datei geschaffen werden. Wegen geteiltem Server war dies hier jedoch keine Option. Daraus ergibt sich auch ein geringerer Nutzen durch ein mögliches Aufsplitten von JavaScript in mehrere kleine Dateien (hier ohnehin <50KB).
  • JavaScript asynchron Laden, Preloading und Priorisierung: Im Prinzip toll – nur zerschießt asynchrones Laden in diesem Fall Teile des Layouts, die mittels jQuery/JS dargestellt werden. Bei nachträglichem Laden greifen die Anweisungen nicht mehr korrekt. Auch das Priorisieren und Vorladen aller above the fold-Inhalte ist nicht trivial. Trotzdem ist dies für die Zukunft vorgemerkt.
  • Server-Side Caching: Geringe Auswirkungen.
  • Content Delivery Networks: Auch diese könnten für eine Beschleunigung sorgen, konkret für die Bereitstellung der zu ladenden Inhalte. Dies lohnt sich (wie bei Server-Side Caching) besonders bei statischen Inhalten.

Außerdem gibt es einige falsche Positive, die man im Grunde nur für Tools behebt. Das kann es wert sein, um die Warnungen/Fehler zu reduzieren und den Blick für echte Probleme zu schärfen. In meinem Fall meckerte Google konsequent, dass ein Bild keine Dimensionen vorgegeben hatte. Das stimmt, aber das umschließende Element hatte diese, was effektiv zum gleichen Ergebnis führt.

Einige Dinge ignoriere ich auch komplett: Wenn jemand das Fenster sehr schmal zieht, werden die Bilder verzerrt. Aber so schmal sind nicht einmal ältere Smartphones, und wer sein Fenster auf 100px Breite zieht, ist selbst schuld, wenn die Darstellung sich vom Sinnvollen entfernt. Und höchstwahrscheinlich ist die-/derjenige eh Techie oder Tester.

Weitere Schritte: Übertragung

Beispielseite Web Core Vitals - Komplettscore 94, Desktop

 

Am Ende stand diese Seite auf 94/100 Punkten bei Page Speed Insights für Desktop; für Mobile knapp darunter und bei web.dev noch ein wenig niedriger im hohen 80er-Bereich. Verbesserungsfähig ist vor allem noch der Largest Contentful Paint. Da der erste Inhalt aber nach 1.9 Sekunden sichtbar ist, kann ich damit leben.

Ein wenig ärgert es mich dennoch, dass ich bei web.dev insgesamt in den riesigen Topf „50-89“ falle. Weitere Optimierungen wären jedoch deutlich aufwendiger und stünden in keinem Verhältnis zum Nutzen.

Die Maßnahmen, die ich an dieser Seite und diesem Template vorgenommen habe, kann ich nun auch auf andere Templates übertragen – oft ergeben sich nur leicht abgewandelte Maßnahmen.

 

Web Core Vitals Results / Score


Fazit

Viele oder alle der hier vorgestellten Methoden, eine Seite zu verbessern, sind im Grunde alt. Oft wurden die entsprechenden Maßnahmen nicht umgesetzt, weil es an Arbeitskraft oder -zeit fehlte, weil es die Wartung erschwert, weil es mit anderen Best Practices kollidierte.

Die schlechte Nachricht: Ja, das ist mehr Aufwand und bedeutet mehr Kosten - mindestens dann, wenn man es nicht gleich zu Anfang einplant.

Die gute Nachricht: Man muss nicht immer alles machen! Oft reichen einige Maßnahmen für ein gutes Ergebnis. Welche das sind, gilt es individuell zu prüfen und den Effekt gegen den Aufwand abzuwägen. Gerne helfen wir Ihnen dabei!

Jetzt beraten lassen!

D. H.
David Hefendehl
Head of Digital Marketing
+49 202 5199 0
david.hefendehl@netzkern.de