PageSpeed Matters
    PageSpeed Matters
    Optimization Techniques · Glossary

    Lazy Loading · Definition & Explanation 2026

    Lazy loading is a performance optimization that defers loading non-critical resources until they are needed — typically when they enter or approach the viewport during scrolling. For image-heavy pages, lazy loading can reduce initial page weight by 50–80%, dramatically improving load time, data usage, and Time to Interactive.

    Native lazy loading via the `loading='lazy'` attribute (supported in all major browsers since 2020) makes implementation trivial — a single HTML attribute defers image loading until the user scrolls near them. The Intersection Observer API provides more granular control for custom implementations, including lazy-loading JavaScript components, videos, and third-party embeds.

    However, lazy loading has a critical caveat: never lazy-load the LCP element. Applying `loading='lazy'` to the hero image — the element that determines Largest Contentful Paint — delays it from loading until the browser determines it's in the viewport, adding 200–500ms to LCP. This is one of the most common performance anti-patterns, and Lighthouse specifically flags it.

    In 2026, the combination of native lazy loading for images, facade patterns for heavy embeds (YouTube, Google Maps, chat widgets), and dynamic `import()` for JavaScript modules creates a comprehensive deferred-loading strategy that keeps initial page weight minimal while ensuring all resources are available when the user needs them.

    Updated 2026-02-28
    M
    By Matt Suffoletto

    TL;DR — Quick Summary

    Lazy loading delays loading offscreen images and iframes until the user scrolls near them, reducing initial page weight by 50–80%. Use native `loading='lazy'` for images/iframes. Never lazy-load the LCP element — use `fetchpriority='high'` instead. Use Intersection Observer for custom lazy-loading of components and embeds.

    What is Lazy Loading?

    Lazy loading is a technique that defers the loading of non-critical resources until they are needed. The browser initially loads only above-the-fold content, then progressively loads additional resources as the user scrolls.

    Native Lazy Loading (`loading='lazy'`): The simplest implementation. Add `loading='lazy'` to `<img>` and `<iframe>` elements. The browser handles all viewport detection and loading timing automatically. The browser uses an internal threshold (typically 1250–2500px below the viewport, varying by connection speed) to start loading before the element scrolls into view.

    Intersection Observer API: A JavaScript API for detecting when elements enter the viewport. Provides more control than native lazy loading — custom thresholds, callbacks, and the ability to lazy-load any element type (not just images/iframes).

    Facade Pattern: A specialized lazy loading technique for heavy third-party embeds. Replace the embed with a lightweight static placeholder (image + play button for YouTube, static map image for Google Maps) that loads the full embed only when the user clicks. This eliminates 200–800KB of JavaScript from initial page load.

    Dynamic Import: JavaScript-level lazy loading using `import()` syntax. Loads JavaScript modules on-demand rather than upfront. Essential for code splitting in React (`React.lazy()`), Vue (async components), and other frameworks.

    The key principle: load what's visible immediately, defer everything else.

    Lazy Loading Thresholds

    MetricGoodNeeds ImprovementPoor
    loading='lazy' supportAll modern browsersIE 11 (no support)N/A
    Intersection ObserverAll modern browsersIE 11 (polyfill needed)N/A

    Google evaluates the 75th percentile (p75) of real-user field data over a rolling 28-day window.

    History & Evolution

    Key milestones:

    • 2006 — Lazy loading concept popularized for images via JavaScript libraries.
    • 2016 — Intersection Observer API introduced, replacing scroll event listeners for viewport detection.
    • 2019 — Chrome 76 adds native `loading='lazy'` attribute — the first browser implementation.
    • 2020 — Firefox and Safari add native lazy loading. All major browsers now support `loading='lazy'`.
    • 2021 — WordPress 5.5 adds native lazy loading to all images automatically. This causes widespread LCP regressions because it lazy-loads hero images too.
    • 2022 — WordPress 6.1 adds `fetchpriority='high'` and skips lazy loading on the first content image, fixing the LCP regression.
    • 2023 — Chrome adjusts lazy-loading thresholds to be connection-speed-aware (starts loading earlier on fast connections, later on slow ones).
    • 2025–2026 — Native lazy loading is the standard. loading='eager' (default) for above-fold, loading='lazy' for below-fold is the established pattern.

    How Lazy Loading is Measured

    Lazy loading effectiveness is measured by comparing initial page weight, request count, and CWV metrics with and without lazy loading:

    Tools for measuring:

    • Chrome DevTools Network panel — Filter by 'Img' to see which images load initially vs on scroll. Check total transfer size at initial load vs after scrolling.
    • Lighthouse — 'Defer offscreen images' audit identifies images that should be lazy-loaded. 'Largest Contentful Paint image was lazily loaded' catches the LCP anti-pattern.
    • WebPageTest — Filmstrip view shows image loading timing. Waterfall shows which images load before and after user scroll simulation.
    • Chrome DevTools Performance panel — Shows image decode events and their impact on main thread work.

    Key rule: Field data (CrUX) determines Google rankings. Lab data (Lighthouse, WebPageTest) is for debugging and iteration.

    Common Causes of Poor Lazy Loading Scores

    Common lazy loading issues that hurt performance:

    1. 1Lazy-loading the LCP image — The #1 lazy loading mistake. Adds 200–500ms to LCP. Never apply loading='lazy' to hero images, banner images, or any image that's the LCP element.
    2. 2Missing image dimensions — Lazy-loaded images without explicit width/height cause layout shifts (CLS) when they load and expand their container.
    3. 3Over-eager thresholds — Custom Intersection Observer implementations that wait until the image is fully in the viewport before loading create a visible 'pop-in' effect. Load 1000–2000px before the viewport.
    4. 4Not lazy-loading heavy embeds — YouTube iframes (800KB+ JS), Google Maps (300KB+ JS), and chat widgets load heavy JavaScript even when below the fold. Use facade patterns instead.
    5. 5Lazy-loading all images on WordPress — WordPress 5.5+ adds loading='lazy' to all images by default, including the first/LCP image. Must be overridden for above-fold images.
    6. 6No fallback for older browsers — While all modern browsers support native lazy loading, some Intersection Observer implementations lack fallbacks for progressive enhancement.

    Frequently Asked Questions

    For step-by-step optimization, platform-specific fixes, code examples, and case studies, read our full guide:

    The Ultimate Guide to Core Web Vitals: How to Pass All Metrics & Boost Rankings in 2026

    Struggling with Lazy Loading?

    Request a free speed audit and we'll identify exactly what's holding your scores back.