Native Lazy Loading in HTML5: When loading="lazy" Helps and When It Hurts
Native lazy loading with loading="lazy" removes the need for JS libraries — but applying it to above-the-fold images quietly wrecks your LCP. Here's how to use it correctly and verify it works.
08 Jul 2026, 12:42 UTC

Your page ships 4 MB of images, but the visitor only ever sees the first two. For years the fix was a JavaScript library built on Intersection Observer. Today, one HTML attribute does the common case natively — but used carelessly, it makes your most important metric worse, not better.
The thesis is simple: loading="lazy" is a genuine win for below-the-fold imagery and a genuine regression when applied indiscriminately. Knowing the difference is the whole skill.
What the attribute actually does
The loading attribute on <img> and <iframe> accepts two values that matter in practice:
lazy— the browser defers fetching the resource until it is near the viewport.eager— the browser fetches immediately, regardless of position. This is the historical default behavior.
"Near the viewport" is deliberately vague. Each browser applies its own distance-from-viewport threshold, and that threshold can vary with network conditions and has changed between releases. Treat the timing as an implementation detail, never as a guarantee. If your logic depends on an image loading at a precise scroll position, you still need JavaScript.
Support is broad in current Chrome, Edge, Firefox, and Safari. Older browsers simply ignore the attribute and load everything eagerly — a safe progressive-enhancement fallback with no polyfill required.
A worked example that avoids layout shift
Here is a long photo gallery done right:
<img src="gallery-01.jpg"
alt="Sunrise over the harbor, taken from the pier"
loading="lazy"
width="800" height="600">The width and height attributes are not decorative. Without them, the browser reserves no space for the deferred image, and the page jumps when it finally loads — a Cumulative Layout Shift penalty that can erase your performance gains. Alternatively, set aspect-ratio in CSS. Either way, reserve the box before the bytes arrive.
For the hero image at the top of the same page, do the opposite:
<img src="hero.jpg" alt="..." fetchpriority="high">Omitting loading (or setting eager) plus fetchpriority="high" tells the browser this image matters most.
The trade-off nobody mentions in the tutorial
Largest Contentful Paint (LCP) — the Core Web Vitals metric measuring when the biggest visible element renders — is very often an image. If that image carries loading="lazy", the browser deliberately delays it, and your LCP score gets worse. Blanket-applying lazy loading via a CMS plugin or a regex over your templates is one of the most common self-inflicted performance regressions on the modern web.
Two more limitations worth knowing:
- Printing and save-page flows. Some browsers skip offscreen deferred images when printing, producing incomplete printouts. If print fidelity matters, test print preview or use a print stylesheet strategy.
- Not a privacy boundary. Scroll prediction and browser heuristics can trigger fetches earlier than you expect. Never rely on lazy loading to guarantee a resource is not requested.
JavaScript libraries still earn their place when you need custom thresholds, placeholder animations, or retry logic. Native lazy loading wins on shipped bytes and simplicity, not on control.
How to verify it actually works
Do not trust the attribute; measure it:
- Open DevTools → Network tab, filter by Img, and load your long page. Offscreen images should produce no requests until you scroll toward them.
- Run a Lighthouse audit before and after. Compare LCP and total bytes on initial load — bytes should drop, LCP should not rise.
- Test in at least two browsers (say, Chrome and Firefox). You will likely see different fetch thresholds, which confirms why you cannot depend on timing.
- Disable JavaScript and repeat. Native lazy loading keeps working — a quick proof you removed a JS dependency rather than added one.
- Check print preview if your audience prints.
The actionable rule: audit your pages, mark everything below the fold loading="lazy" with reserved dimensions, and explicitly protect your LCP candidate with eager loading. Fifteen minutes of attribute hygiene, verified in the Network tab, beats another JavaScript dependency almost every time.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.