Best Practices für Lazy Loading

Auch wenn Lazy Loading für Bilder und Videos positive und messbare Vorteile in Bezug auf die Leistung bietet, ist es keine leichte Aufgabe. Eine falsche Antwort kann unbeabsichtigte Folgen haben. Daher ist es wichtig, folgende Bedenken zu bedenken.

„Mind the fold“

Es mag verlockend sein, jede einzelne Medienressource auf der Seite mit JavaScript zu laden, aber Sie müssen dieser Versuchung widerstehen. Alles, was „above the fold“ liegt, sollte kein Lazy-Loading sein. Solche Ressourcen sollten als kritische Assets betrachtet und daher normal geladen werden.

Lazy Loading verzögert das Laden von Ressourcen, bis das DOM interaktiv ist, wenn das Laden der Skripts abgeschlossen ist und mit der Ausführung begonnen wurde. Für Bilder „below the fold“ ist das kein Problem. Wichtige Ressourcen „above the fold“ sollten jedoch mit dem Standardelement <img> geladen werden, damit sie so schnell wie möglich angezeigt werden.

Natürlich ist es heutzutage nicht so klar, wo der Fold zu finden ist, wenn Websites auf so vielen Bildschirmen unterschiedlicher Größe aufgerufen werden. Was bei einem Laptop "above the fold" (ohne Scrollen sichtbar) liegt, kann auf Mobilgeräten unterhalb liegen. Es gibt keine allgemeingültigen Ratschläge, wie Sie in jeder Situation optimal umgehen können. Sie müssen eine Bestandsaufnahme der wichtigen Assets Ihrer Seite erstellen und diese Bilder wie gewohnt laden.

Außerdem sollten Sie die Faltlinie nicht so genau festlegen, wie der Grenzwert zum Auslösen von Lazy Loading ist. Für Ihre Zwecke ist es möglicherweise besser, eine Pufferzone mit einem Abstand zum unteren Rand des ohne Scrollen sichtbaren Bereichs einzurichten, damit die Bilder schon lange geladen werden, bevor der Nutzer sie in den Darstellungsbereich scrollt. Mit der Intersection Observer API können Sie beispielsweise ein rootMargin-Attribut in einem Optionsobjekt angeben, wenn Sie eine neue IntersectionObserver-Instanz erstellen. Dadurch wird für die Elemente ein Zwischenspeicher bereitgestellt, der das Lazy Loading-Verhalten 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-margin-Property angeben würdest, liegt das genau daran. In diesem Fall wird der untere Rand des beobachteten Elements um 256 Pixel erweitert. Standardmäßig ist das der Darstellungsbereich des Browsers. Dieser kann jedoch mithilfe der Eigenschaft root zu einem bestimmten Element geändert werden. Die Callback-Funktion wird also ausgeführt, wenn sich ein Bildelement innerhalb von 256 Pixeln des Darstellungsbereichs befindet und das Bild geladen wird, bevor der Nutzer es sieht.

Um diesen Effekt in Browsern zu erzielen, die Intersection Observe nicht unterstützen, verwenden Sie Code für die Verarbeitung von Scroll-Ereignissen und passen Sie die getBoundingClientRect-Prüfung so an, dass sie einen Puffer einschließt.

Layout Shifts und Platzhalter

Lazy Loading von Medien kann zu Verschiebungen im Layout 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. Sie sollten zumindest einen Platzhalter für eine Volltonfarbe verwenden, der die gleichen Abmessungen wie das Zielbild einnimmt, oder Verfahren wie LQIP oder SQIP verwenden, die auf den Inhalt eines Medienelements hinweisen, bevor es geladen wird.

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

Verzögerungen bei der Bilddecodierung

Wenn große Bilder in JavaScript geladen und in das DOM abgelegt werden, kann dadurch der Hauptthread verbunden werden. Dies führt dazu, dass die Benutzeroberfläche während der Decodierung kurzzeitig nicht reagiert. Wenn Sie Bilder mit der Methode decode asynchron decodieren, bevor sie in das DOM eingefügt werden, können diese Art von Verzögerungen reduziert werden. Aber Vorsicht: Sie ist noch nicht überall verfügbar und erhöht die Komplexität der Lazy-Load-Logik. 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 Code, der diesem Beispiel ähnelt, in Aktion sehen. Wenn die meisten Ihrer Bilder relativ klein sind, bringt das möglicherweise nicht viel, aber es kann sicherlich dazu beitragen, Verzögerungen beim Lazy Loading großer Bilder und beim Einfügen in das DOM zu vermeiden.

Wenn etwas nicht geladen wird

Manchmal können Medienressourcen aus einem bestimmten Grund nicht geladen werden und es treten Fehler auf. Wann könnte das passieren? Das kommt darauf an, aber hier ist ein hypothetisches Szenario: Sie haben für einen kurzen Zeitraum (z.B. fünf Minuten) eine Richtlinie für das HTML-Caching und der Nutzer besucht die Website oder hat einen veralteten Tab für längere Zeit (z.B. mehrere Stunden) geöffnet und kehrt zurück, um Ihre Inhalte zu lesen. An einem bestimmten Punkt dieses Prozesses findet eine erneute Bereitstellung statt. Während dieser Bereitstellung ändert sich der Name einer Bildressource aufgrund der hashbasierten Versionsverwaltung oder wird vollständig entfernt. Wenn der Nutzer das Image per Lazy Loading lädt, ist die Ressource nicht mehr verfügbar und schlägt daher fehl.

Dies kommt zwar relativ selten vor, aber wenn das Lazy Loading fehlschlägt, kann es von Vorteil sein, einen Sicherungsplan zu haben. Für Bilder 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önnten beispielsweise den Bildplatzhalterbereich durch eine Schaltfläche ersetzen, mit der der Nutzer versuchen kann, das Bild noch einmal zu laden, oder einfach eine Fehlermeldung im Bildplatzhalterbereich anzeigen zu lassen.

Es können aber auch andere Szenarien eintreten. Was auch immer Sie tun, es ist nie eine schlechte Idee, dem Nutzer zu signalisieren, wenn ein Fehler aufgetreten ist, und ihm vielleicht eine Handlung zu geben, wenn etwas schiefgeht.

Verfügbarkeit von JavaScript

Es darf nicht davon ausgegangen werden, dass JavaScript immer verfügbar ist. Wenn du Lazy Loading für Bilder verwendest, kannst du auch <noscript>-Markup verwenden, das Bilder anzeigt, wenn JavaScript nicht verfügbar ist. Das einfachste mögliche Fallback-Beispiel ist die Verwendung von <noscript>-Elementen zur Bereitstellung von Bildern, wenn JavaScript deaktiviert ist:

Ich bin ein Bild!

Wenn JavaScript deaktiviert ist, sehen Nutzer sowohl das Platzhalterbild als auch das Bild, das in den <noscript>-Elementen enthalten ist. Um das zu umgehen, platziere die Klasse no-js so in das <html>-Tag:

<html class="no-js">

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

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

Schließlich können Sie CSS-Code verwenden, um Elemente mit der Klasse „lazy“ auszublenden, wenn JavaScript nicht verfügbar ist:

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

Dies verhindert nicht, dass Platzhalterbilder geladen werden, aber das Ergebnis ist wünschenswerter. Nutzer, für die JavaScript deaktiviert ist, erhalten mehr als nur Platzhalterbilder. Sie sind also besser als Platzhalter und haben überhaupt keinen aussagekräftigen Bildinhalt.