Lazy Loading
Definition: Lazy Loading (verzögertes Laden) ist eine Performance-Optimierungstechnik, bei der Ressourcen – Bilder, Videos, iframes, JavaScript-Module – nicht beim initialen Seitenaufruf geladen werden, sondern erst wenn sie in den sichtbaren Viewport-Bereich des Nutzers scrollen oder anderweitig benötigt werden. Ohne Lazy Loading wird der gesamte Ressourcenbedarf einer langen Seite sofort angefordert, auch wenn der Nutzer nur den oberen Bereich sieht. Native Lazy Loading für Bilder und iframes ist via HTML-Attribut «loading="lazy"» ohne JavaScript implementierbar. Für JavaScript-Module bieten dynamische import()-Statements und Framework-Features (React.lazy, Vue defineAsyncComponent) Code-Splitting-basiertes Lazy Loading. Korrekt eingesetzt verbessert Lazy Loading LCP, FID und Core Web Vitals – falsch eingesetzt (auf LCP-Bild angewandt) verschlechtert es sie.
Erläuterung
Lazy Loading hat zwei unabhängige Anwendungsbereiche: (1) Medien-Lazy-Loading für Bilder, Videos und iframes – reduziert initiale HTTP-Requests und Datenmenge; (2) JavaScript-Lazy-Loading via Code Splitting – reduziert initialen JavaScript-Bundle und damit Time to Interactive. Beide verbessern Performance, erfordern aber unterschiedliche Implementierungen. Der häufigste Fehler: loading="lazy" auf das Hero-Bild (LCP-Element) setzen und sich wundern warum der LCP-Score schlechter wird.
Natives Bild-Lazy-Loading
- loading="lazy"-Attribut: <img src="product.jpg" loading="lazy" alt="...">; Browser lädt Bild wenn es ~mehrere Viewports vom sichtbaren Bereich entfernt ist; kein JavaScript nötig; Browser-Unterstützung: alle modernen Browser (Chrome 77+, Firefox 75+, Safari 15.4+); keine Polyfill-Notwendigkeit für aktuelle Browser-Targets
- LCP-Konflikt: Kritischster Fehler: loading="lazy" auf das LCP-Bild (größtes Above-the-fold-Bild) setzen; Browser priorisiert lazy Images niedrig → LCP verzögert sich; Regel: alle Bilder above the fold explizit loading="eager" (Standard) oder mit fetchpriority="high"; loading="lazy" nur für Bilder below the fold
- fetchpriority-Attribut: fetchpriority="high" für LCP-Bild priorisiert Browser-Download; kombiniert mit <link rel="preload"> im <head> für frühen Fetch; seit 2023 in Chrome und Safari unterstützt; Lighthouse-Empfehlung für LCP-Optimierung
- iframes lazy laden: <iframe loading="lazy"> für YouTube-Embeds, Google Maps, Chat-Widgets; YouTube-Iframe: ~400 KB Ressourcen die erst beim Scrollen geladen werden; Facade Pattern: ersetzt iframe initial durch Screenshot-Bild, lädt echten iframe erst bei Klick (youtube-lite.js)
JavaScript-Lazy-Loading
- Dynamic Import: import('./heavyModule.js').then(module => module.doSomething()); Modul wird erst bei Aufruf geladen; Webpack/Vite splitten automatisch separate Chunk-Dateien; für selten genutzte Features (Modal, Chart-Bibliothek, Video-Player)
- React.lazy + Suspense: const HeavyChart = React.lazy(() => import('./HeavyChart')); <Suspense fallback={<Spinner />}><HeavyChart /></Suspense>; Component wird erst geladen wenn sie gerendert werden soll; Fallback während Ladezeit sichtbar; standard für große React-Anwendungen
- Route-basiertes Lazy Loading: Jede Route/Seite als eigener Chunk; Nutzer lädt nur JavaScript der aktuell besuchten Seite; Startseite-Bundle 50 KB statt 500 KB für gesamte App; React Router + React.lazy: Standard-Pattern für SPAs
Intersection Observer API
- Wann IntersectionObserver statt loading="lazy": Für Custom-Lazy-Loading-Logik; Animationen die beim Einblenden starten; Analytics-Tracking ob Nutzer ein Element gesehen hat (impression tracking); Video-Autoplay wenn im Viewport; Komplexere Logik als natives loading-Attribut
- Grundimplementierung: const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { loadContent(entry.target); observer.unobserve(entry.target); }})}); observer.observe(element); unobserve nach erstem Auslösen für Performance
- Impression Tracking: Sichtbarkeits-Tracking für Werbebanner, Content-Cards, Produktlisten; IntersectionObserver mit threshold: 0.5 (50 % sichtbar); Custom Event in GA4 wenn Element im Viewport; Marketing-Analytics: welche Produkte wurden tatsächlich gesehen?
Core-Web-Vitals-Impact
- LCP-Impact: Lazy Loading auf Below-the-fold-Bilder: positiv (weniger Bandbreite für initiales Laden); Lazy Loading auf LCP-Bild: negativ (LCP-Zeit steigt deutlich); Regel: Bilder im ersten Viewport immer eager laden
- CLS-Risiko: Bilder ohne width/height-Attribute verursachen CLS beim Lazy-Load; Lösung: immer Dimensionen im <img>-Tag angeben (width="800" height="600") damit Browser Platz reserviert; aspect-ratio CSS-Eigenschaft als Alternative
- Lighthouse-Diagnose: «Defer offscreen images» = Lazy Loading fehlt für Below-the-fold-Bilder; zeigt potenzielle Einsparung in KB; «Largest Contentful Paint element» zeigt ob LCP-Element fälschlicherweise lazy geladen wird