Best Practices für Lazy Loading

Lazy Loading von Bildern und Videos hat zwar positive und messbare Leistungsvorteile, muss aber nicht leichtfertig betrachtet werden. Wenn Sie falsch liegen, kann das ungewollte Folgen haben. Daher ist es wichtig, die folgenden Bedenken zu berücksichtigen.

„Mind the fold“

Es mag verlockend sein, jede einzelne Medienressource auf der Seite mit JavaScript zu laden, aber Sie sollten dieser Versuchung widerstehen. Alles, was ohne Scrollen sichtbar ist, sollte nicht Lazy Loading sein. Solche Ressourcen sollten als kritische Assets betrachtet werden und daher normal geladen werden.

Beim Lazy Loading wird das Laden von Ressourcen so lange verzögert, bis das DOM interaktiv ist und die Skripts fertig geladen sind und mit der Ausführung begonnen haben. Bei Bildern „below the fold“ ist das in Ordnung. Wichtige Ressourcen „above the fold“ sollten jedoch mit dem Standardelement <img> geladen werden, damit sie so schnell wie möglich angezeigt werden.

Heutzutage, wo Websites auf so vielen Bildschirmen unterschiedlicher Größe angezeigt werden, ist natürlich nicht klar, wo der „Fold“ liegt. Auf Laptops können Elemente, die ohne Scrollen sichtbar sind, auf Mobilgeräten unterhalb platziert werden. Es gibt keine pauschale Empfehlung, um in jeder Situation optimal darauf zu reagieren. Sie müssen eine Bestandsaufnahme der wichtigsten Assets Ihrer Seite durchführen und diese Bilder dann normalerweise laden.

Außerdem ist es nicht sinnvoll, die Faltlinie als Schwellenwert für Lazy Loading zu definieren. Für Ihre Zwecke ist es möglicherweise besser, einen Pufferbereich in einem bestimmten Abstand unterhalb des Seitenumbruchs festzulegen, damit die Bilder geladen werden, bevor der Nutzer sie in den Darstellungsbereich scrollt. Mit der Intersection Observer API können Sie beispielsweise beim Erstellen einer neuen IntersectionObserver-Instanz ein rootMargin-Attribut in einem Optionsobjekt angeben. Dadurch erhalten Elemente einen Puffer, der das Lazy Loading auslöst, bevor sich das Element im Darstellungsbereich befindet:

let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
  // lazy-loading image code goes here
}, {
  rootMargin: "0px 0px 256px 0px"
});

Wenn der Wert für rootMargin den Werten ähnelt, die du für eine CSS-Eigenschaft margin angeben würdest, liegt das daran. In diesem Fall wird der untere Rand des beobachteten Elements (standardmäßig der Darstellungsbereich des Browsers, der mit der Eigenschaft root in ein bestimmtes Element geändert werden kann) um 256 Pixel erweitert. Das bedeutet, dass die Callback-Funktion ausgeführt wird, wenn sich ein Bildelement nicht mehr als 256 Pixel vom Darstellungsbereich entfernt befindet und das Bild geladen wird, bevor der Nutzer es tatsächlich sieht.

Um den gleichen Effekt in Browsern zu erzielen, die Intersection Observe nicht unterstützen, verwenden Sie Code zur Verarbeitung von Scroll-Ereignissen und passen Sie die getBoundingClientRect-Prüfung so an, dass sie einen Zwischenspeicher enthält.

Layout Shifts und Platzhalter

Lazy Loading von Medien kann zu Layoutverschiebungen führen, wenn keine Platzhalter verwendet werden. Diese Änderungen können für Nutzer verwirrend sein und teure DOM-Layoutvorgänge auslösen, die Systemressourcen verbrauchen und zu Verzögerungen führen. Verwenden Sie mindestens einen Platzhalter für Volltonfarbe, der dieselben Abmessungen wie das Zielbild einnimmt, oder verwenden Sie Techniken wie LQIP oder SQIP, die Hinweise auf den Inhalt eines Medienelements geben, bevor es geladen wird.

Bei <img>-Tags sollte src zuerst auf einen Platzhalter verweisen, bis dieses Attribut mit der finalen Bild-URL aktualisiert wird. Verwenden Sie das Attribut poster in einem <video>-Element, um auf ein Platzhalterbild zu verweisen. Verwenden Sie außerdem die Attribute width und height sowohl für <img>- als auch für <video>-Tags. Dadurch wird beim Übergang von Platzhaltern zu endgültigen Bildern die gerenderte Größe des Elements nicht geändert, wenn Medien geladen werden.

Verzögerungen bei der Decodierung von Bildern

Wenn große Bilder in JavaScript geladen und in das DOM verschoben werden, kann der Hauptthread zu stressig werden, wodurch die Benutzeroberfläche während der Decodierung für kurze Zeit nicht mehr reagiert. Durch das asynchrone Decodieren von Bildern mit der Methode decode vor dem Einfügen in das DOM kann diese Art von Verzögerung reduziert werden. Achtung: Die Funktion ist noch nicht überall verfügbar und macht die Lazy Loading-Logik komplex. Wenn Sie es verwenden möchten, müssen Sie danach suchen. Im Folgenden wird gezeigt, wie Sie Image.decode() mit einem Fallback verwenden können:

var newImage = new Image();
newImage.src = "my-awesome-image.jpg";

if ("decode" in newImage) {
  // Fancy decoding logic
  newImage.decode().then(function() {
    imageContainer.appendChild(newImage);
  });
} else {
  // Regular image load
  imageContainer.appendChild(newImage);
}

Über diesen CodePen-Link können Sie einen ähnlichen Code wie dieses Beispiel in Aktion sehen. Wenn die meisten Ihrer Bilder relativ klein sind, ist das vielleicht nicht viel für Sie, aber es kann sicherlich dazu beitragen, Verzögerungen beim Lazy Loading großer Bilder und Einfügen in das DOM zu verringern.

Wenn Daten nicht geladen werden

Manchmal werden Medienressourcen aus verschiedenen Gründen nicht geladen und es können Fehler auftreten. Wann könnte dies geschehen? Das kommt darauf an, aber hier ist ein hypothetisches Szenario: Sie haben für einen kurzen Zeitraum (z.B. fünf Minuten) eine HTML-Caching-Richtlinie und der Nutzer besucht die Website oder ein Nutzer hat einen veralteten Tab (z.B. mehrere Stunden) geöffnet und kehrt zurück, um Ihre Inhalte zu lesen. An einem Punkt in diesem Prozess wird eine erneute Bereitstellung durchgeführt. Während dieser Bereitstellung ändert sich der Name einer Bildressource aufgrund der hashbasierten Versionsverwaltung oder wird vollständig entfernt. Sobald der Nutzer das Bild per Lazy Loading lädt, ist die Ressource nicht mehr verfügbar und schlägt daher fehl.

Auch wenn dies relativ selten ist, kann es sein, dass Sie einen Sicherungsplan haben, wenn Lazy Loading fehlschlägt. Bei Bildern könnte eine solche Lösung in etwa so aussehen:

var newImage = new Image();
newImage.src = "my-awesome-image.jpg";

newImage.onerror = function(){
  // Decide what to do on error
};
newImage.onload = function(){
  // Load the image
};

Was Sie im Falle eines Fehlers tun, hängt von Ihrer Anwendung ab. Sie können beispielsweise den Bildplatzhalterbereich durch eine Schaltfläche ersetzen, über die der Nutzer versuchen kann, das Bild noch einmal zu laden, oder einfach eine Fehlermeldung im Bildplatzhalterbereich anzeigen.

Auch andere Szenarien könnten hinzukommen. In jedem Fall ist es nie eine schlechte Idee, dem Nutzer zu signalisieren, dass ein Fehler aufgetreten ist, und ihn möglicherweise zu einer Aktion zu bewegen, wenn etwas nicht klappt.

Verfügbarkeit von JavaScript

Es sollte nicht davon ausgegangen werden, dass JavaScript immer verfügbar ist. Wenn du Lazy Loading für Bilder vornimmst, kannst du <noscript>-Markup anbieten, damit Bilder angezeigt werden, falls JavaScript nicht verfügbar ist. Im einfachsten Fall können Sie ein Fallback-Beispiel verwenden, indem <noscript>-Elemente zur Bereitstellung von Bildern verwendet werden, wenn JavaScript deaktiviert ist:

Ich bin ein Bild!

Wenn JavaScript deaktiviert ist, sehen Nutzer sowohl das Platzhalterbild als auch das Bild mit den <noscript>-Elementen. Um dieses Problem zu umgehen, fügen Sie eine Klasse von no-js in das <html>-Tag ein:

<html class="no-js">

Fügen Sie dann eine Zeile des Inline-Skripts im <head> ein, bevor Stylesheets über <link>-Tags angefordert werden. Dadurch wird die Klasse no-js aus dem Element <html> entfernt, wenn JavaScript aktiviert ist:

<script>document.documentElement.classList.remove("no-js");</script>

Verwenden Sie schließlich CSS, um Elemente mit einer Klasse von Lazy auszublenden, wenn JavaScript nicht verfügbar ist:

.no-js .lazy {
  display: none;
}

Das verhindert nicht, dass Platzhalterbilder geladen werden, aber das Ergebnis ist erstrebenswert. Nutzer, für die JavaScript deaktiviert ist, sehen mehr als Platzhalterbilder – besser als Platzhalter und ohne aussagekräftige Bildinhalte.