zurück zum Artikel

Lazy Loading Images mit Custom Elements

Hilko Holweg

Ein Blick in den Quellcode von heise online fördert seit einiger Zeit kaum noch -Tags zutage, sondern zumeist . Was das ist und wieso wir das machen, wollen wir hier einmal erlÀutern.

Ein Blick in den Quellcode von heise online fördert seit einiger Zeit kaum noch <img>-Tags zutage, sondern zumeist <a-img>. Was das ist und wieso wir das machen, wollen wir hier einmal erlÀutern.

An Bilder im Internet sind die letzten Jahre zunehmend höhere AnsprĂŒche gestellt worden. GenĂŒgte jahrelang das einfache <img>-Tag, kamen mit Responsive Layouts und High-DPI-Displays immer mehr Anforderungen, die nur gemĂ€chlich Einzug in die Standards hielten. Des Weiteren ist das Web bildreicher geworden. Lange Seiten laden zig Bilddateien herunter, die User eventuell nie sehen. Das Nachladen von Grafiken (Lazy Loading), wenn User sich durch Scrollen den Bildern annĂ€hern, dient hier also vor allem der Performance und schont auf MobilgerĂ€ten das Datenvolumen. FĂŒr uns als Serverbetreiber ist es ebenso von Vorteil, nur die Daten zu ĂŒbertragen, die die User auch tatsĂ€chlich nutzen.

Mehr Infos

Web Components

Web Components sind eine Sammlung von Techniken, um wiederverwendbare, in sich geschlossene Komponenten zu erstellen. Kerntechniken dabei sind Custom Elements, Shadow-DOM, HTML imports und HTML Template.

Siehe dazu auf heise Developer:

Custom Elements sind Teil des Web-Components-Standards [4] und noch recht frisch. Da nicht alle Browser ihre Implementierungen abgeschlossen haben, sind aktuell noch Polyfills zur Nutzung nötig, die wir nur den Browsern ausliefern, die das entsprechende Feature noch nicht kennen.

In HTML beziehungsweise in Browsern war es schon immer möglich, <meintag> ins DOM einzufĂŒgen und es einfach zu benutzen. Das war jedoch nicht konform mit dem HTML-Standard und konnte zu unterschiedlichen Problemen fĂŒhren. Custom Elements hingegen ermöglichen es, dem Browser eigene Tags beizubringen. Als Bedingung fĂŒr die Bezeichnung sticht vor allem heraus, dass das Tag einen Bindestrich haben muss, also zum Beispiel <mein-tag>. Im JavaScript wird dieses Tag dann dem Browser bekannt gemacht und die Funktion beschrieben.

Custom Elements sollen helfen, wiederverwendbare Komponenten zu schreiben; die eigene Tag-Bezeichnung darf hier als Namespacing verstanden werden. Ist ein Custom Element einmal dem Browser bekannt gemacht, kann es wie jedes andere Tag problemlos auch asynchron nachtrĂ€glich ins DOM eingefĂŒgt werden und funktioniert sofort. DarĂŒber hinaus ist bei der Verwendung des optionalen Shadow DOM der Scope immer automatisch auf das aktuelle Custom Element beschrĂ€nkt, mit dem interagiert wird.

Wieso haben wir nun eigentlich ĂŒberhaupt ein Bild als Custom Element gelöst? Vorweg: Am Ende landet im DOM auch wieder nur ein altbekanntes <img>, jedoch geschachtelt in unserem Custom Element <a-img>. Das <img> wird allerdings an den aktuellen User angepasst. Die BildgrĂ¶ĂŸe richtet sich am Elternelement aus (meist ein <figure>), das je nach Breakpoint beziehungsweise GerĂ€t des Users (Smartphone, Tablet, Desktop) unterschiedlich groß sein kann. Wir mĂŒssen hier nicht mittels Media Query auf alles vorbereitet sein – das erledigt das JavaScript fĂŒr uns und fordert eine entsprechende Variante des Bildes vom Server an.

Neben der reinen BildgrĂ¶ĂŸe analysiert das JavaScript auch, ob es sich um ein High-DPI-Display handelt, und baut dann eine hochauflösende Variante ein. In Zukunft wĂ€re es auch möglich, die Bandbreite des Users mit einfließen zu lassen ("Network Information API") und bei lahmer Verbindung trotz High-DPI-Display nur eine niedriger aufgelöste Grafik zu senden.

Der Nachteil an Media Queries ist, dass sie sich immer auf die Viewport-GrĂ¶ĂŸe beziehen. Wird also ein Bild in einer Randspalte mit nur 200 Pixel Breite angezeigt, greift dieselbe Media Query wie beim großen Aufmacherbild mit 600 Pixel Breite im Artikel. Hier mĂŒsste also fĂŒr jedes etwaige Vorkommen eines Bildes in unterschiedlicher GrĂ¶ĂŸe ein eigenes Set an Media Queries geschrieben werden. Da macht es das JavaScript einfacher, das sich am verfĂŒgbaren Platz und der tatsĂ€chlichen GrĂ¶ĂŸe des Bildes orientiert.

Drei ZustÀnde eines Bildes, wie es per Lazy Loading geladen wird

Lazy-Loading bei der Arbeit

Neben einem möglichst optimalen Bild, was im Prinzip auch bereits mit <img>, srcset- und sizes-Attributen und dem <picture>-Tag möglich wĂ€re, kann <a-img> aber auch Lazy Loading. Das heißt, Bilder die gar nicht im Viewport des Users sind, werden auch nicht geladen. Bewegt der User das Bild allerdings in Richtung des Viewports (z. B. durch Scrollen) wird es geladen. Dank Custom Element mĂŒssen wir hier jedoch keine Verrenkungen machen, wie man es in der Vergangenheit getan hat ("1px.gif", leere src-Attribut etc.). <a-img> kĂŒmmert sich darum, dass das <img> erst geladen und eingebunden wird, wenn sich der User tatsĂ€chlich in die NĂ€he des Bildes bewegt – aktuell bei uns eine Bildschirmhöhe des Users. DafĂŒr verwenden wir die Intersection Observer API, ebenfalls eine neue Technik, die es endlich erlaubt solche Operationen ohne EventListener auf das scroll-Event vorzunehmen, das ja immer wieder einige Probleme mit sich gebracht hat.

Intersection Observer sind außerdem asynchron und blockieren somit nicht den Main-Thread. Ein weiteres Feature ist, dass man eine Zone um das zu observierende Element herum definieren kann ("rootMargin"), das eine Aktion auslöst. Konkret bedeutet das, Bilder werden nicht erst geladen, wenn sie auch tatsĂ€chlich im Viewport sind, sondern wir können bereits schon vorher – beispielsweise wenn das Bild noch 500 Pixel vom Viewport entfernt ist – das Laden des Bildes initiieren. Damit ist die Wahrscheinlichkeit hoch, dass es bereits fertig geladen ist, wenn der User beim Bild angekommen ist.

Bei Codepen haben wir ein reduziertes Beispiel von <a-img> hinterlegt [5], das nur die Funktion des Lazy Loading mittels Intersection Observer umfasst. Um das Beispiel einfach zu halten, funktioniert es in der vorliegenden Fassung nur mit aktuellen Browsern, die alle Features bereits von Haus aus unterstĂŒtzen (beispielsweise der aktuelle Chrome oder Firefox Nightly).

Mit der Integration sind wir aktuell recht zufrieden. Uns ist jedoch bewusst, dass hier viele neue Techniken zusammenkommen, die gerade in Ă€lteren Browsern teils nicht funktionieren. Polyfills helfen dabei eine Menge, aber auch nicht immer. Beispielsweise haben wir im IE11 starke Performance-Probleme feststellen mĂŒssen, sodass das JavaScript lediglich einmalig ein <img>-Tag ausliefert, das dann leider kein Lazy Loading beherrscht oder auf Display-VerĂ€nderungen reagiert. Auch den <noscript>-Fall haben wir nicht außer Acht gelassen, hier wird ebenfalls ein einfaches <img>-Tag ausgegeben.

Wer sich ĂŒbrigens gefragt hat, weshalb wir "a-" als PrĂ€fix gewĂ€hlt haben: Das beruht auf unserem selbst entwickelten hausinternen Frontend-Framework "akwa", ĂŒber das wir sicherlich ein anderes Mal noch berichten werden. (hih [6])


URL dieses Artikels:
https://www.heise.de/-4175606

Links in diesem Artikel:
[1] https://www.heise.de/hintergrund/Martin-Splitt-Web-Components-das-unbekannte-Wesen-aus-dem-Browser-3725798.html
[2] https://www.heise.de/blog/Episode-55-Pro-und-Contra-von-Web-Components-3606844.html
[3] https://www.heise.de/ratgeber/Zukunft-der-Webentwicklung-Webkomponenten-und-Progressive-Web-Apps-Teil-1-3355449.html
[4] https://www.webcomponents.org/
[5] https://codepen.io/maczarr/pen/oMZbNr
[6] mailto:hih@heise.de