Bilder in React lazy laden, ohne LCP zu beeinträchtigen
Um ein Bild in React lazy zu laden, rendern Sie ein normales Element vom Typ
img mit loading="lazy". Hinterlegen Sie die echte URL in
src, ergänzen Sie srcSet und
sizes, sobald responsive Varianten verfügbar sind, und geben Sie
width und height an, damit der Browser Platz
reservieren kann.
Die wichtige Ausnahme ist das Bild, das auf der Seite voraussichtlich zum Element für den Largest Contentful Paint (LCP) wird. Belassen Sie dieses Bild bei eager und sorgen Sie dafür, dass es im initialen HTML auffindbar ist. Lazy Loading verzögert genau die Anfrage, die die Seite am dringendsten schnell abschließen muss.
| Rolle des Bildes | Ladeentscheidung | Weiteres wichtiges Markup |
|---|---|---|
| Hero-Bild oder wahrscheinliches LCP-Bild | Eager | fetchPriority="high", sofern bestätigt |
| Weiteres im ersten Viewport sichtbares Bild | Eager | Abmessungen und responsive Quellen |
| Gewöhnliches Inhaltsbild außerhalb des Viewports | Lazy | src, srcSet, sizes und Abmessungen |
| Dekorativer CSS-Hintergrund | Eigener Mechanismus | Bedeutungstragende Inhalte in img nicht ersetzen |
„Above the fold“ ist keine feste Anzahl von Bildern. Viewport-Höhe, responsive Layouts, Banner und lokalisierte Inhalte können dasselbe Bild in den initialen Viewport verschieben oder daraus entfernen. Ordnen Sie Bilder anhand der gerenderten Seite ein und überprüfen Sie die Entscheidung anschließend auf repräsentativen Bildschirmgrößen.
Die native loading-Prop von React verwenden
React reicht die Prop loading an das native Bildelement des Browsers weiter.
Für ein gewöhnliches Bild außerhalb des Viewports brauchen Sie keinen Effect, keinen Scroll-Handler
und keine Intersection-Observer-Bibliothek.
import type { ReactNode } from 'react'
interface ResponsiveImageProps {
alt: string
height: number
sizes: string
src: string
srcSet: string
width: number
}
export function ResponsiveImage({
alt,
height,
sizes,
src,
srcSet,
width,
}: ResponsiveImageProps): ReactNode {
return (
<img
className="responsive-image"
src={src}
srcSet={srcSet}
sizes={sizes}
width={width}
height={height}
loading="lazy"
decoding="async"
alt={alt}
/>
)
}
Hinterlegen Sie eine echte Bild-URL in src. Wenn Sie die einzige URL in
ein eigenes Attribut data-src verschieben, hängt die Anfrage von Ihrem
JavaScript ab und der Preload-Scanner des Browsers kann sie im normalen Bild-Markup nicht mehr
entdecken. Außerdem bleibt das Bild ungeladen, wenn das Skript fehlschlägt.
Die Prop decoding="async" ist ein separater Hinweis zum Decodieren. Sie entscheidet
nicht, wann die Netzwerkanfrage startet, und sie ersetzt loading="lazy" nicht.
Verwenden Sie die Komponente in einer Liste wie jede andere React-Komponente:
<ResponsiveImage
src="/images/workshop-960.webp"
srcSet="/images/workshop-480.webp 480w, /images/workshop-960.webp 960w"
sizes="(max-width: 40rem) 100vw, 40rem"
width={960}
height={640}
alt="A technician calibrating a camera rig"
/>
Lazy Loading verändert nur den Startzeitpunkt der Anfrage. Es nimmt keine Größenänderung vor und komprimiert, konvertiert, cacht oder beschreibt das Bild nicht.
Das LCP-Bild eager laden
Wenden Sie loading="lazy" nicht auf ein wahrscheinliches LCP-Bild an. Rendern Sie
dessen URL im initialen HTML, sofern Ihr React-Framework serverseitiges Rendern unterstützt, damit
der Browser sie findet, ohne auf clientseitiges Rendern oder eine weitere Datenanfrage warten zu
müssen.
import type { ReactNode } from 'react'
export function HeroImage(): ReactNode {
return (
<img
className="responsive-image"
src="/images/harbor-1280.webp"
srcSet="/images/harbor-640.webp 640w, /images/harbor-1280.webp 1280w"
sizes="100vw"
width={1280}
height={720}
loading="eager"
fetchPriority="high"
alt="Fishing boats returning to the harbor at sunrise"
/>
)
}
fetchPriority="high" ist ein relativer Prioritätshinweis und keine Garantie für die
Reihenfolge der Anfragen. Reservieren Sie ihn für das gemessene LCP-Bild. Wenn mehrere Bilder als
hoch priorisiert markiert sind, hat der Browser weniger nützliche Informationen, um zu entscheiden,
welches am wichtigsten ist.
Ein Bild kann auf Mobilgeräten das LCP-Element sein, auf Desktops dagegen nicht, oder umgekehrt. Bestätigen Sie mit Felddaten zur Performance, welches Element bei echten Besuchern zum LCP wird, statt anzunehmen, dass jedes große Bild oder jede Karussell-Folie kritisch ist.
Lazy Loading mit responsiven Bildern kombinieren
Eine verzögerte Anfrage kann trotzdem eine unnötig große Datei herunterladen. Mit
Breitendeskriptoren wie 480w liefert srcSet die
Kandidatendateien, und sizes beschreibt die Breite des gerenderten
Anzeigebereichs. Der Browser kombiniert diese Informationen mit der Pixeldichte des Geräts und wählt
einen Kandidaten aus.
Schreiben Sie sizes für das Layout, nicht für die Quelldatei. Wenn ein Bild
auf dem Smartphone den gesamten Viewport einnimmt und auf breiteren Bildschirmen eine 640 Pixel
breite Spalte, geben Sie genau das an:
<img
className="responsive-image"
src="/images/product-960.webp"
srcSet="/images/product-480.webp 480w, /images/product-960.webp 960w"
sizes="(max-width: 40rem) 100vw, 40rem"
width={960}
height={640}
loading="lazy"
decoding="async"
alt="Red trail shoe viewed from the side"
/>
Der Browser führt für eager und lazy geladene Bilder dieselbe responsive Kandidatenauswahl durch.
Die Ladeentscheidung macht korrekte Kandidaten und einen präzisen Wert für
sizes nicht überflüssig.
Platz reservieren, um Layout-Verschiebungen zu vermeiden
Geben Sie für jedes Inhaltsbild width und height
an. Browser berechnen aus diesen Attributen ein Seitenverhältnis, bevor das Bild heruntergeladen
ist, und reservieren so genau den richtigen Platz im Layout. Ihr CSS kann das Bild trotzdem fluide
machen:
.responsive-image {
display: block;
height: auto;
max-width: 100%;
}
Die Attribute müssen das intrinsische Seitenverhältnis des Bildes beschreiben. Ein Element vom Typ
img kann zum Beispiel width={960} und
height={640} verwenden, wenn jeder Kandidat ein Verhältnis von 3:2 hat, selbst
wenn der Browser eine 480×320 große Datei auswählt. Wenn Quellen mit Art Direction unterschiedliche
Zuschnitte oder Seitenverhältnisse verwenden, müssen ihre Abmessungen die ausgewählte Quelle
beschreiben und nicht einen unabhängigen Fallback.
Reservierter Bildplatz verhindert eine Ursache von Cumulative Layout Shift (CLS), aber nicht jede mögliche Verschiebung. Bildunterschriften, Werbung, Consent-Elemente, Schriften und Fehlermeldungen können die Seite weiterhin verschieben.
Wann Intersection Observer angebracht ist
Nutzen Sie für gewöhnliche Bilder das native Ladeverhalten des Browsers. Greifen Sie nur dann zu
Intersection Observer, wenn die Komponente ein Verhalten benötigt, das sich mit
loading="lazy" nicht ausdrücken lässt, etwa das Starten einer Animation, das
Erfassen eines Sichtbarkeitsereignisses oder das Anwenden eines aufwendigen dekorativen
Hintergrunds, kurz bevor er den Viewport erreicht.
Mounten Sie ein normales Inhaltsbild nicht erst bedingt, nachdem ein Observer ausgelöst hat, sofern
dieses Verhalten nicht wirklich erforderlich ist. Bedingtes Mounten verzögert die Auffindbarkeit,
fügt einen JavaScript-Fehlerpfad hinzu und zwingt Sie dazu, einen stabilen Fallback zu entwerfen.
Bedeutungstragende Bilder sollten Elemente vom Typ img oder
picture bleiben und über nützlichen Alternativtext verfügen.
React.lazy() löst ein anderes Problem: Es verzögert das Laden eines
JavaScript-Komponentenmoduls. Bildanfragen, die diese Komponente rendert, werden dadurch nicht
automatisch verzögert.
Responsive Derivate mit Transloadit erzeugen
Lazy Loading kann ein überdimensioniertes Quellbild nicht reparieren. Eine praxistaugliche Auslieferungs-Pipeline erzeugt eine kleine, begrenzte Menge an Breiten, optimiert jedes Ergebnis, exportiert die Ergebnisse in einen dauerhaften Speicher und hält deren URLs und Abmessungen für die React-Ansicht fest.
Der Robot /image/resize von Transloadit kann diese Breitenvarianten erzeugen, und der Robot /image/optimize kann die unterstützten Ergebnisse optimieren:
{
"steps": {
"small": {
"robot": "/image/resize",
"use": ":original",
"width": 480,
"resize_strategy": "fit",
"zoom": false,
"format": "webp"
},
"medium": {
"robot": "/image/resize",
"use": ":original",
"width": 960,
"resize_strategy": "fit",
"zoom": false,
"format": "webp"
},
"large": {
"robot": "/image/resize",
"use": ":original",
"width": 1440,
"resize_strategy": "fit",
"zoom": false,
"format": "webp"
},
"small_optimized": {
"robot": "/image/optimize",
"use": "small"
},
"medium_optimized": {
"robot": "/image/optimize",
"use": "medium"
},
"large_optimized": {
"robot": "/image/optimize",
"use": "large"
}
}
}
Das Beispiel verwendet zoom: false, damit ein kleiner Upload nicht allein deshalb
vergrößert wird, um eine Zielbreite zu erreichen. Ergänzen Sie nach der Verarbeitung einen Robot für
die Speicherung oder einen anderen Export-Step, der zu Ihrer Architektur passt, und verwenden Sie
anschließend diese dauerhaften Auslieferungs-URLs in src und
srcSet. Ergebnis-URLs einer Assembly sind temporäre Verarbeitungsausgaben
und kein dauerhafter Speicher für Ihre Anwendung. Die verfügbaren Storage-Integrationen finden Sie
beim Dateiexport-Service. Warten Sie nicht darauf, dass die
React-Komponente Derivate erzeugt. Wenn Sie freigegebene Breiten lieber bei Bedarf transformieren
und cachen möchten, lesen Sie die Anleitung zum Ausliefern responsiver Bilder über eine einzige
URL.
Die React-Anwendung entscheidet weiterhin über die Darstellung: welches Bild bedeutungstragend ist, welchen Alternativtext es hat, wie groß sein gerenderter Anzeigebereich ist und ob es anfangs kritisch ist. Transloadit übernimmt die Medienverarbeitung und entscheidet nicht, welches Bild in einem bestimmten Seitenlayout zum LCP wird.
Das Ergebnis messen
Prüfen Sie die Produktionsseite, statt sich nur auf den Quellcode der Komponente zu verlassen:
- Zeichnen Sie in den Entwicklertools des Browsers Ladevorgänge mit schmalem und breitem Viewport bei kaltem Cache auf.
- Bestätigen Sie, dass die Anfrage für das LCP-Bild früh startet und nicht als lazy markiert ist.
- Scrollen Sie und prüfen Sie, ob gewöhnliche Bilder außerhalb des Viewports verzögert geladen werden, ohne für Nutzer zu spät zu erscheinen.
- Untersuchen Sie den ausgewählten Kandidaten aus
srcSetund vergleichen Sie dessen Abmessungen mit dem gerenderten Anzeigebereich. - Messen Sie LCP und CLS anhand von Felddaten, gruppiert nach Seitenvorlage und relevantem Viewport.
- Blockieren Sie Bildanfragen, um nützlichen Alternativtext und stabile Fehlerzustände zu überprüfen. Wenn die Seite serverseitiges Rendern unterstützt, prüfen Sie zusätzlich das serverseitig gerenderte Ergebnis vor der Hydration.
Die Abstände und die Planung beim Lazy Loading hängen von der jeweiligen Browser-Implementierung ab. Vermeiden Sie eine Regel wie „ab dem dritten Bild alles lazy laden“ oder einen angenommenen festen Pixelschwellenwert. Messen Sie die Seiten und Geräte, die Ihre Nutzer tatsächlich erhalten.
Häufige Fehler beim Lazy Loading in React
- Das Hero-Bild oder das gemessene LCP-Bild lazy laden.
- Die einzige Bild-URL von
srcnachdata-srcverschieben. - Kritische Bilder erst rendern, nachdem clientseitiger Code oder eine Datenanfrage abgeschlossen ist.
srcSetohne einen präzisen Wert fürsizesangeben.widthundheightweglassen, weil das CSS am Ende die Bildgröße steuert.- Jedes Bild mit
fetchPriority="high"markieren. - Eine Observer-Bibliothek nur einsetzen, um natives Browser-Verhalten nachzubilden.
- Annehmen, dass
React.lazy()die Netzwerkanfragen für Bilder steuert. - Eine 3.000 Pixel große Quelle verzögert laden, statt ein passendes Derivat zu erzeugen.
Die verlässliche Standardvorgehensweise ist einfach: vollständiges Bild-Markup rendern, wahrscheinliche LCP-Bilder eager laden, gewöhnliche Bilder außerhalb des Viewports lazy laden und jede angeforderte Datei passend zu dem Anzeigebereich wählen, in dem sie dargestellt wird.
Die zugrunde liegenden Browser-Regeln finden Sie im Standard für Lazy Loading in HTML, im LCP-Leitfaden von web.dev und in dessen Leitfaden zu responsiven Bildern.
