Zwei Logos in der Fußzeile einer Kundenwebsite blieben leer. Kein Platzhalter, kein kaputtes Bild-Symbol — nur Leerraum, wo sie hätten stehen sollen.
Der Server lieferte beide Dateien mit HTTP 200. Die Pfade stimmten, die Dateien lagen im Projekt, der Build war zufrieden. Alles grün.
Die Ursache steht im Bild-Tag
<img src="/assets/logo.png" loading="lazy" alt="Logo">Das Attribut loading="lazy" weist den Browser an, das Bild erst anzufordern, wenn es in die Nähe des sichtbaren Bereichs kommt. Die Fußzeile lag rund 12.000 Pixel unter dem oberen Seitenrand. Sie kam nie in die Nähe — also wurde nie angefordert.
Das ist kein Fehler des Browsers. Er tut genau, was dasteht.
Warum jede naheliegende Prüfung grün meldet
Der Reflex ist, die Datei zu prüfen: Liegt sie da? Antwortet der Server? Stimmt der Pfad? Alle drei Fragen ergeben ein Ja — und keine davon trifft das Problem. Der Server wurde nie gefragt.
Sichtbar wird es nur am gerenderten Element:
[...document.querySelectorAll('img')].map(i => ({
src: i.getAttribute('src'),
geladen: i.complete && i.naturalWidth > 0
}))naturalWidth: 0 bei einer Datei, die per curl 200 liefert, heißt: angefordert wurde nichts. Das ist der Unterschied zwischen "die Datei ist erreichbar" und "das Bild ist geladen".
Wohin lazy gehört — und wohin nicht
Das Attribut ist für Bilder im Inhaltsfluss gedacht: lange Artikel, Galerien, Produktlisten, durch die jemand scrollt. Dort spart es echte Ladezeit.
Nicht gehört es an Fußzeilen, Logos, Signaturen, Herkunftsvermerke — alles, was unter einer langen Seite hängt und das jemand vielleicht nie erreicht. Wenn das Dekodieren stört, ist decoding="async" das richtige Mittel: Es entkoppelt die Verarbeitung, ohne den Abruf zu verhindern.
Was wir daraus mitnehmen
Nach jedem Einbau von Bildern messen wir naturalWidth über alle Bilder der Seite — nicht den Statuscode der Dateien. Am gerenderten Gegenstand messen, nicht an der Quelle.
Der Fall gehört zu einer Familie: Auch Einblend-Animationen, die an den sichtbaren Bereich gekoppelt sind, können Inhalte dauerhaft verstecken, wenn die Auslösung nie stattfindet. Immer wenn der Viewport darüber entscheidet, ob etwas erscheint statt nur wann, lohnt ein zweiter Blick.