Ein tiefer Einblick in natives Lazy-Loading für Bilder und Frames

Avatar of Erk Struwe
Erk Struwe am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Heutige Websites sind vollgestopft mit schweren Medieninhalten wie Bildern und Videos. Bilder machen etwa 50% des durchschnittlichen Datenverkehrs einer Website aus. Viele davon werden jedoch nie für einen Benutzer angezeigt, da sie weit unterhalb des sichtbaren Bereichs platziert sind.

Was hat es mit dem Lazy-Loading von Bildern auf sich, fragst du dich? Lazy-Loading wurde hier auf CSS-Tricks bereits ziemlich oft behandelt, einschließlich eines ausführlichen Leitfadens mit Dokumentation für verschiedene Ansätze mit JavaScript. Kurz gesagt, wir sprechen hier von einem Mechanismus, der den Netzwerktraffic zum Laden von Inhalten verzögert, bis er benötigt wird – oder besser gesagt, bis der Ladevorgang ausgelöst wird, wenn der Inhalt in den Viewport gelangt.

Der Vorteil? Eine kleinere initiale Seite, die schneller lädt und Netzwerkanfragen für Elemente spart, die möglicherweise nicht benötigt werden, wenn der Benutzer nie dorthin gelangt.

Wenn Sie andere Lazy-Loading-Anleitungen auf dieser oder anderen Websites lesen, werden Sie sehen, dass wir verschiedene Taktiken anwenden mussten, um Lazy-Loading zu ermöglichen. Nun, das wird sich ändern, wenn Lazy-Loading nativ in HTML als neues Attribut loading verfügbar sein wird… zumindest in Chrome, was hoffentlich zu einer breiteren Akzeptanz führen wird. Chrome entwickelt und testet derzeit die Unterstützung für natives Lazy-Loading und wird es voraussichtlich in Chrome 76 aktivieren, das für den 30. Juli 2019 geplant ist.

Eager cat loaded lazily (but still immediately because it's above the fold)

Der Pre-Native-Ansatz

Bisher mussten Entwickler wie wir JavaScript (sei es eine Bibliothek oder etwas von Grund auf Geschriebenes) verwenden, um Lazy-Loading zu erreichen. Die meisten Bibliotheken funktionieren so:

  • Die initiale, serverseitige HTML-Antwort enthält ein img-Element ohne das Attribut src, sodass der Browser keine Daten lädt. Stattdessen wird die URL des Bildes als weiteres Attribut im Datensatz des Elements gesetzt, z. B. data-src.
  • <img data-src="https://tiny.pictures/example1.jpg" alt="...">
  • Anschließend wird eine Lazy-Loading-Bibliothek geladen und ausgeführt.
  • <script src="LazyLoadingLibrary.js"></script>
    <script>LazyLoadingLibrary.run()</script>
  • Diese verfolgt das Scrollverhalten des Benutzers und weist den Browser an, das Bild zu laden, wenn es kurz davor ist, in den sichtbaren Bereich gescrollt zu werden. Dies geschieht durch Kopieren des Werts des Attributs data-src in das zuvor leere Attribut src.
  • <img src="https://tiny.pictures/example1.jpg" data-src="https://tiny.pictures/example1.jpg" alt="...">

Das funktioniert nun schon seit geraumer Zeit und erfüllt seinen Zweck. Aber aus guten Gründen ist es nicht ideal.

Das offensichtliche Problem dieses Ansatzes ist die Länge des kritischen Pfades für die Anzeige der Website. Er besteht aus drei Schritten, die nacheinander ausgeführt werden müssen:

  1. Laden der initialen HTML-Antwort
  2. Laden der Lazy-Loading-Bibliothek
  3. Laden der Bilddatei

Wenn diese Technik für Bilder oberhalb des sichtbaren Bereichs verwendet wird, flackert die Website während des Ladens, da sie zuerst ohne das Bild gerendert wird (nach Schritt 1 oder 2, je nachdem, ob das Skript defer oder async verwendet) und dann – nach dem Laden – das Bild enthält. Sie wird auch als langsam ladend wahrgenommen.

Darüber hinaus belastet die Lazy-Loading-Bibliothek selbst das Bandbreite und die CPU-Anforderungen der Website zusätzlich. Und vergessen wir nicht, dass ein JavaScript-Ansatz bei Personen, die JavaScript deaktiviert haben, nicht funktioniert (obwohl wir uns im Jahr 2019 wirklich keine Sorgen um sie machen sollten, sollten wir das?).

Ach ja, und was ist mit Websites, die sich zur Verbreitung von Inhalten auf RSS verlassen, wie CSS-Tricks? Das initiale rendern ohne Bilder bedeutet, dass auch in der RSS-Version des Inhalts keine Bilder vorhanden sind.

Und so weiter.

Natives Lazy-Loading zur Rettung!

Lazy cat loaded lazily

Wie wir zu Beginn bemerkt haben, werden Chromium und Google Chrome einen nativen Mechanismus für Lazy-Loading in Form eines neuen Attributs loading einführen, beginnend mit Chrome 75. Wir werden uns das Attribut und seine Werte gleich ansehen, aber lassen Sie uns zuerst sehen, wie es in unseren Browsern funktioniert, damit wir es gemeinsam ausprobieren können.

Natives Lazy-Loading aktivieren

In Chrome-Versionen ab 75 können wir Lazy-Loading manuell aktivieren, indem wir zwei Flags umschalten. Es wird erwartet, dass Chrome diese Funktion ab Version 76 (Veröffentlichung für den 30. Juli 2019 geplant) standardmäßig aktiviert.

  1. Öffnen Sie chrome://flags in Chromium oder Chrome Canary.
  2. Suchen Sie nach lazy.
  3. Aktivieren Sie sowohl das Flag „Enable lazy image loading“ als auch das Flag „Enable lazy frame loading“.
  4. Starten Sie den Browser mit der Schaltfläche in der unteren rechten Ecke des Bildschirms neu.
Flags für natives Lazy-Loading in Google Chrome

Sie können überprüfen, ob die Funktion ordnungsgemäß aktiviert ist, indem Sie Ihre JavaScript-Konsole öffnen (F12). Sie sollten folgende Warnung sehen:

[Intervention] Images loaded lazily and replaced with placeholders. Load events are deferred.

Alles klar? Nun wollen wir uns das loading-Attribut ansehen.

Das loading-Attribut

Sowohl die Elemente img als auch iframe akzeptieren das Attribut loading. Es ist wichtig zu beachten, dass seine Werte vom Browser nicht als strenge Anweisung, sondern eher als Hinweis behandelt werden, um dem Browser bei seiner eigenen Entscheidung zu helfen, ob das Bild oder der Frame lazy geladen werden soll oder nicht.

Das Attribut kann drei Werte haben, die unten erklärt werden. Neben den Bildern finden Sie Tabellen mit den individuellen Ladezeiten Ihrer Ressourcen für diesen Seitenaufruf. Range Response bezieht sich auf eine Art teilweisen Pre-Flight-Request zur Ermittlung der Bildabmessungen (siehe How it works für Details). Wenn diese Spalte ausgefüllt ist, hat der Browser eine erfolgreiche Range-Anfrage durchgeführt.

Bitte beachten Sie die Spalte startTime, die angibt, wann das Laden des Bildes nach dem Parsen des DOM verzögert wurde. Möglicherweise müssen Sie einen Hard-Reload (CTRL + Shift + R) durchführen, um Range-Anfragen erneut auszulösen.

Der Auto- (oder unset-) Wert

<img src="auto-cat.jpg" loading="auto" alt="...">
<img src="auto-cat.jpg" alt="...">
<iframe src="https://css-tricks.de/" loading="auto"></iframe>
<iframe src="https://css-tricks.de/"></iframe>
Auto cat loaded automatically
Auto-Katze wurde automatisch geladen

Wenn das Attribut loading auf auto gesetzt wird (oder der Wert einfach leer gelassen wird, wie in loading=""), kann der Browser entscheiden, ob ein Bild lazy geladen werden soll oder nicht. Er berücksichtigt viele Dinge, um diese Entscheidung zu treffen, wie z. B. die Plattform, ob der Datensparmodus aktiviert ist, Netzwerkbedingungen, Bildgröße, Bild im Vergleich zu iframe, die CSS-Eigenschaft display und andere. (Siehe How it works für Informationen, warum das alles wichtig ist.)

Der Eager-Wert

<img src="auto-cat.jpg" loading="eager" alt="...">
<iframe src="https://css-tricks.de/" loading="eager"></iframe>
Eager cat loaded eagerly
Eager-Katze wurde eifrig geladen

Der Wert eager gibt dem Browser einen Hinweis, dass ein Bild sofort geladen werden sollte. Wenn das Laden bereits verzögert wurde (z. B. weil es auf lazy gesetzt und dann per JavaScript auf eager geändert wurde), sollte der Browser das Bild sofort laden.

Der Lazy-Wert

<img src="auto-cat.jpg" loading="lazy" alt="...">
<iframe src="https://css-tricks.de/" loading="lazy"></iframe>
Lazy cat loaded lazily
Lazy-Katze wurde lazy geladen

Der Wert lazy gibt dem Browser einen Hinweis, dass ein Bild lazy geladen werden soll. Es liegt am Browser, genau zu interpretieren, was das bedeutet, aber das Erklärungsdokument besagt, dass er beginnen soll, das Bild zu laden, wenn der Benutzer "in die Nähe" des Bildes scrollt, sodass es wahrscheinlich geladen ist, sobald es tatsächlich in den sichtbaren Bereich gelangt.

Wie das loading-Attribut funktioniert

Im Gegensatz zu JavaScript-Lazy-Loading-Bibliotheken verwendet natives Lazy-Loading eine Art Pre-Flight-Request, um die ersten 2048 Bytes der Bilddatei abzurufen. Mit diesen versucht der Browser, die Abmessungen des Bildes zu ermitteln, um einen unsichtbaren Platzhalter für das vollständige Bild einzufügen und zu verhindern, dass Inhalte während des Ladens springen.

Das load-Ereignis des Bildes wird ausgelöst, sobald das vollständige Bild geladen ist, sei es nach der ersten Anfrage (für Bilder kleiner als 2 KB) oder nach der zweiten. Beachten Sie, dass das load-Ereignis für bestimmte Bilder möglicherweise nie ausgelöst wird, da die zweite Anfrage nie gestellt wird.

In Zukunft werden Browser möglicherweise doppelt so viele Bildanfragen stellen wie im aktuellen Vorschlag. Zuerst die Range-Anfrage, dann die vollständige Anfrage. Stellen Sie sicher, dass Ihre Server den HTTP-Header Range: 0-2047 unterstützen und mit dem Statuscode 206 (Partial Content) antworten, um zu verhindern, dass das vollständige Bild zweimal geliefert wird.

Aufgrund der höheren Anzahl aufeinanderfolgender Anfragen desselben Benutzers wird die Webserverunterstützung für das HTTP/2-Protokoll wichtiger.

Lassen Sie uns über verzögerte Inhalte sprechen. Chromes Rendering-Engine Blink verwendet Heuristiken, um zu bestimmen, welche Inhalte verzögert werden sollen und wie lange. Eine umfassende Liste der Anforderungen finden Sie in Scott Littles Design-Dokumentation. Hier ist eine kurze Zusammenfassung dessen, was verzögert wird:

  • Bilder und Frames auf allen Plattformen, auf denen loading="lazy" gesetzt ist
  • Bilder auf Chrome für Android mit aktiviertem Datensparmodus, die alle folgenden Kriterien erfüllen:
    • loading="auto" oder nicht gesetzt
    • keine width- und height-Attribute kleiner als 10px
    • nicht programmgesteuert in JavaScript erstellt
  • Frames, die alle folgenden Kriterien erfüllen:
    • loading="auto" oder nicht gesetzt
    • stammen von einem Drittanbieter (andere Domäne oder Protokoll als die einbettende Seite)
    • größer als 4 Pixel in Höhe und Breite (um das Verzögern winziger Tracking-Frames zu verhindern)
    • nicht als display: none oder visibility: hidden markiert (auch hier, um das Verzögern von Tracking-Frames zu verhindern)
    • nicht durch negative x- oder y-Koordinaten außerhalb des Bildschirms positioniert

Responsive Bilder mit srcset

Natives Lazy-Loading funktioniert auch mit responsiven img-Elementen, die das Attribut srcset verwenden. Dieses Attribut bietet dem Browser eine Liste von Bilddateikandidaten. Basierend auf der Bildschirmgröße des Benutzers, dem Anzeige-Pixelverhältnis, den Netzwerkbedingungen usw. wählt der Browser den optimalen Bildkandidaten für die jeweilige Situation aus. Bildoptimierungs-CDNs wie tiny.pictures können alle Bildkandidaten in Echtzeit ohne jegliche Backend-Entwicklung bereitstellen.

<img src="https://demo.tiny.pictures/native-lazy-loading/lazy-cat.jpg" srcset="https://demo.tiny.pictures/native-lazy-loading/lazy-cat.jpg?width=400 400w, https://demo.tiny.pictures/native-lazy-loading/lazy-cat.jpg?width=800 800w" loading="lazy" alt="...">

Browser-Unterstützung

Zum Zeitpunkt der Erstellung unterstützt kein Browser natives Laden standardmäßig. Chrome wird die Funktion jedoch, wie berichtet, ab Chrome 76 einführen. Bisher hat kein anderer Browserhersteller Unterstützung angekündigt. (Edge ist in gewisser Weise eine Ausnahme, da es bald auf Chromium umsteigen wird.)

Sie können die Funktion mit ein paar Zeilen JavaScript erkennen:

if ("loading" in HTMLImageElement.prototype) {
  // Support.
} else {
  // No support. You might want to dynamically import a lazy-loading library here (see below).
}

Siehe den Pen
Native lazy-loading browser support
von Erk Struwe (@erkstruwe)
auf CodePen.

Automatische Fallback-Lösung mit JavaScript und Low-Quality-Image-Placeholder

Eine sehr coole Funktion der meisten JavaScript-basierten Lazy-Loading-Bibliotheken ist der Low-Quality Image Placeholder (LQIP). Im Grunde nutzt er die Idee, dass Browser den src eines img-Elements sofort laden (oder vielleicht sollte ich sagen früher geladen haben), auch wenn er später durch eine andere URL ersetzt wird. So ist es möglich, beim Seitenaufruf eine sehr kleine, qualitativ minderwertige Bilddatei zu laden und sie später durch eine vollwertige Version zu ersetzen.

Dies können wir nun nutzen, um die 2 KB Range-Anfragen des nativen Lazy-Loadings in Browsern zu imitieren, die diese Funktion nicht unterstützen, um das gleiche Ergebnis zu erzielen, nämlich einen Platzhalter mit den tatsächlichen Bildabmessungen und einer winzigen Dateigröße.

Siehe den Pen
Native lazy-loading with JavaScript library fallback and low-quality image placeholder
von Erk Struwe (@erkstruwe)
auf CodePen.

Fazit

Ich bin wirklich begeistert von dieser Funktion. Und ehrlich gesagt wundere ich mich, warum sie bisher nicht mehr Aufmerksamkeit erhalten hat, angesichts der Tatsache, dass ihre Veröffentlichung unmittelbar bevorsteht und die Auswirkungen auf den globalen Internetverkehr bemerkenswert sein werden, selbst wenn nur kleine Teile der Heuristiken geändert werden.

Denken Sie darüber nach: Nach einer schrittweisen Einführung für die verschiedenen Chrome-Plattformen und mit auto als Standardeinstellung wird der beliebteste Browser der Welt bald standardmäßig Bilder und Frames unterhalb des sichtbaren Bereichs per Lazy-Loading laden. Nicht nur die Datenmenge vieler schlecht geschriebener Websites wird erheblich sinken, sondern Webserver werden mit winzigen Anfragen zur Bildgrößenerkennung bombardiert.

Und dann ist da noch das Tracking: Angenommen, viele ahnungslose Tracking-Pixel und Frames werden nicht geladen, müssen die Analyse- und Affiliate-Industrie reagieren. Wir können nur hoffen, dass sie nicht in Panik geraten und loading="eager" zu jedem einzelnen Bild hinzufügen, was diese großartige Funktion für ihre Benutzer nutzlos macht. Sie sollten eher ihren Code ändern, um von den Heuristiken, die oben beschrieben sind, als Tracking-Pixel erkannt zu werden.

Webentwickler, Analyse- und Betriebsmanager sollten das Verhalten ihrer Website mit dieser Funktion und die Unterstützung ihrer Server für Range-Anfragen und HTTP/2 sofort überprüfen.

Bildoptimierungs-CDNs könnten helfen, falls es Probleme zu erwarten gibt oder wenn Sie die Optimierung der Bildlieferung auf das Äußerste treiben möchten (einschließlich automatischer WebP-Unterstützung, Low-Quality-Image-Placeholdern und vielem mehr). Lesen Sie mehr über tiny.pictures!

Referenzen