Lazy loading

On this page 7

Lazy loading is a web performance technique that defers the loading of resources until they are needed, typically until an image or iframe approaches the viewport or until a feature is actually used. Instead of downloading everything at page load, the browser fetches only what the first view requires and postpones the rest.

Applied well, lazy loading reduces initial bytes, network contention and main-thread work, which helps metrics such as Largest Contentful Paint and Total Blocking Time. Applied to the wrong element, especially the main above-the-fold image, it delays exactly the content the user is waiting for.

How lazy loading defers resources

Lazy loading replaces an eager request with a deferred request triggered by a condition. For media, the condition is usually distance from the viewport; for code, it is a route change or a user action. The browser or a script watches for that condition and only then starts the network request.

With native lazy loading, the developer adds loading="lazy" to an img or iframe element. The browser keeps the element in the DOM, skips the fetch, and starts it once the element comes within a browser-defined distance threshold of the viewport. Chromium-based browsers use thresholds of roughly 1,250 to 2,500 pixels, depending on connection speed, so images usually arrive before they scroll into view.

Script-based lazy loading relies on the Intersection Observer API. A placeholder carries the real address in a data-src attribute, an observer with a rootMargin such as 200px reports when it nears the viewport, and the script then swaps in the real source. This approach still matters for background images, custom components and fine-grained control.

Types of lazy loading and what they defer

Lazy loading is a family of techniques, not one attribute. Each variant defers a different kind of resource and needs a different trigger.

FormResource deferredTypical triggerImplementation
Native image lazy loadingBelow-the-fold imagesDistance from viewportloading="lazy" on img
Iframe lazy loadingEmbedded videos, maps, widgetsDistance from viewportloading="lazy" on iframe
Observer-based loadingBackground images, custom elementsIntersection with root marginIntersection Observer API
Code lazy loadingJavaScript modules and componentsRoute change or interactionDynamic import() with code splitting
Facade patternHeavy third-party embedsClick on a lightweight previewStatic image replaced on demand
Data lazy loadingList items, comments, feedsScroll position or paginationFetch on demand
Main forms of lazy loading

Code lazy loading is closely tied to code splitting: a module bundler splits the application into chunks, and the dynamic import() call loads a chunk only when a route or dialog needs it. The facade pattern often gives the largest savings, because a single video embed can pull in several hundred kilobytes of script before the user presses play.

Effects on Core Web Vitals and loading metrics

Lazy loading changes what competes for bandwidth and CPU in the first seconds. Its effect on each metric depends on whether deferred resources belong to the first view.

MetricEffect when applied correctlyEffect when misapplied
LCPImproves by freeing bandwidth for the hero elementWorsens if the LCP image is lazy
CLSNeutral when dimensions are reservedWorsens if images lack width and height
INP and TBTImproves when deferred code is never parsed earlyWorsens if large chunks load on first click
Total page weightFalls for users who never scrollUnchanged for users who read everything
Speed IndexUsually improves through faster first viewWorsens with visible blank placeholders
How lazy loading influences key metrics

The most frequent regression is a lazily loaded LCP image. The browser cannot start the request until layout confirms the image position, which typically adds hundreds of milliseconds compared with an eager request discovered by the preload scanner. Hero images should stay eager and may receive fetchpriority="high" or a preload hint.

Lazy loading compared with preload, prefetch and eager loading

Lazy loading is one of several resource prioritization strategies. It lowers priority by postponing a request, while preload and prefetch move requests earlier.

StrategyTiming of the requestBest suited to
Eager loadingAs soon as the parser discovers itContent in the first view
Lazy loadingWhen needed or near the viewportBelow-the-fold media and optional features
PreloadEarly, at high priorityCritical late-discovered assets such as fonts
PrefetchDuring idle time, low priorityResources for a likely next navigation
Resource loading strategies side by side

These strategies are complementary. A well-tuned page preloads its critical assets, eagerly loads the first view, lazy loads the rest and prefetches the next likely page during idle time.

Implementation choices and common mistakes

A safe default is to lazy load everything below the first viewport and nothing within it. Because the first viewport differs between phones and desktops, many teams keep the first two or three images eager and lazy load the remainder of long lists.

MistakeSymptomFix
Lazy hero imageSlow LCP, late visible contentLoad it eagerly with high fetch priority
Missing dimensionsContent jumps as images arriveSet width and height or aspect-ratio
Scroll event listenersJanky scrolling, extra main-thread workUse native loading or Intersection Observer
Lazy content hidden from crawlersText or images missing from search indexesKeep real elements in HTML, avoid scroll-only triggers
Too small root marginBlank images during fast scrollingLoad earlier with a larger margin
Frequent mistakes and how to fix them

Search engines render pages but do not scroll like users, so content that loads only after scroll or interaction may never be seen. Native attributes and observer-based loading of real elements are crawler-friendly; content injected after infinite scrolling needs paginated fallback URLs.

A plain-language summary

Imagine a restaurant that cooks every dish on the menu the moment a guest sits down. The kitchen would be overloaded and the first plate would arrive late. A sensible restaurant cooks each dish when it is ordered.

Lazy loading applies the same idea to web pages. The browser first fetches what is visible on the screen and waits to fetch the pictures, videos and features further down until the reader is about to reach them. The page appears faster, and visitors who never scroll never pay for content they did not see.

An example from practice

An online furniture store has category pages with 48 product photos and an embedded video guide near the bottom. Every photo is about 120 KB, so a phone on a mobile network downloads nearly 6 MB of images before the page settles, and the hero banner competes with all of them for bandwidth.

The team keeps the banner and the first four product photos eager, gives the banner high fetch priority, adds loading="lazy" with explicit dimensions to the remaining photos, and replaces the video with a click-to-play facade. Initial transfer drops to under 1 MB, the measured LCP on mid-range phones improves by roughly one second, and layout shift stays near zero because every image reserves its space.