File Formats & Media

Lazy Loading

Definition

The browser sees the element in the markup but holds off on the request until the viewport approaches it, then fetches normally. Native support landed in Chrome 76 in 2019, Firefox 75 in 2020 and Safari 15.4 in March 2022, so it now works essentially everywhere without a line of JavaScript. It applies to img and iframe elements. How close is close enough is left to the implementation and changes with connection speed — Chrome starts fetching several thousand pixels ahead on a slow connection and much later on a fast one, which is why images normally appear before you reach them. The older approach, an IntersectionObserver watching placeholder elements, is now only a fallback for very old browsers.

Why It Matters

On a long page the saving is immediate: a gallery of forty thumbnails where a visitor sees six becomes six requests instead of forty, perhaps 300 KB instead of 2 MB. The trap is applying it everywhere. If the hero image is the Largest Contentful Paint element and it carries the lazy attribute, the browser deliberately delays discovering and requesting it, and the metric gets worse — regressions of several hundred milliseconds are typical and a full second is not unusual. The rule that follows is easy to remember: anything visible without scrolling loads eagerly, everything below the fold loads lazily, and the hero can be pushed further forward with a high fetchpriority. Lazy loading is a way to defer work, not a way to make work faster.

How It Works

Add the loading attribute with the value lazy to an img, and give that img width and height attributes as well — without dimensions the browser cannot reserve space, so the layout shifts as each image arrives and the page takes a CLS penalty for it. An aspect-ratio rule in CSS does the same job for fluid images. Iframes take the same attribute, which is a good way to stop an embedded map or video player pulling a third-party bundle nobody scrolls to. The separate decoding attribute, set to async, hints that the image may be decoded off the main thread, which helps with large photographs. All of this combines happily with srcset: the browser still picks the right candidate, it just picks it later. None of it needs a build step, so it works on plain static hosting.

Real-World Example

A sixty-photo event gallery is published on 99helpers at gallery-night.99helpers.site. Loaded eagerly it made 96 requests for 8.4 MB and reached its largest paint at 4.1 seconds. Marking everything below the first row as lazy, leaving the first three images eager and giving the lead photograph a high fetch priority brought the initial payload to 1.1 MB and the largest paint to 1.6 seconds, with no visible change for anyone scrolling through the whole set.

Common Mistakes

  • Applying the lazy attribute to every image on the page, including the hero — the largest visible element is then discovered late and the page measures slower than before
  • Omitting width and height — each arriving image pushes the content below it down, which is the most irritating kind of layout shift
  • Keeping a JavaScript lazy-loading library alongside the native attribute — the two fight, and the script is a dependency the page no longer needs
  • Lazy loading content that search engines or link previews need to see — anything essential should be in the markup and fetched normally

Related Terms

Put a file online in seconds

Drop in a document, an image, a page or a whole static website and share the link — free, with no build step and no server to set up.

Host a file free →