Lazy-load with loading="lazy".
One attribute, no JS.
The loading="lazy" attribute tells the browser to defer loading an image or iframe until it's near the viewport. The benefit is a faster initial page load: fewer bytes downloaded, less bandwidth used, faster First Contentful Paint. No JavaScript, no IntersectionObserver code, no library. This page covers how it works, when to use it, and — more importantly — when not to.
Short answer: Add loading="lazy" to images and iframes that are below the fold. Do not add it to the hero image, the logo, or anything visible on first paint — that delays LCP and slows the page. All modern browsers support it since 2020. Older browsers ignore it and load eagerly — no risk of breakage.
✅ When to use it
The rule is simple: above the fold, eager. Below the fold, lazy.
✅ Use on below-fold images
Images in footers, long articles, product grids, comment sections, anything the user has to scroll to see.
✅ Use on iframes
YouTube embeds, maps, third-party widgets. These are often the heaviest elements on the page.
❌ Don't use on hero images
The hero is above the fold. Lazy-loading it delays LCP and hurts page speed scores.
❌ Don't use on logos or nav icons
Small, above-the-fold, part of first paint. Eager is correct here.
✅ Before and after
The same page, with and without lazy loading.
<img src="hero.jpg" alt="Hero"> <!-- 50 images below, all eager by default --> <img src="product-1.jpg" alt="Product 1"> <img src="product-2.jpg" alt="Product 2"> <img src="product-3.jpg" alt="Product 3"> <!-- ... 47 more ... -->
❌ All 51 images load on first paint. ❌ Page downloads 5-15 MB before user scrolls. ❌ Slow FCP, slow LCP, slow Time to Interactive. ❌ Mobile users on slow connections get a blank page for several seconds.
<!-- Hero: eager (no loading attribute) --> <img src="hero.jpg" alt="Hero"> <!-- Below-fold: lazy --> <img src="product-1.jpg" alt="Product 1" loading="lazy"> <img src="product-2.jpg" alt="Product 2" loading="lazy"> <img src="product-3.jpg" alt="Product 3" loading="lazy"> <!-- ... 47 more, all with loading="lazy" ... -->
✅ Hero loads immediately (LCP protected). ✅ Only ~4 visible images load on first paint. ✅ Page downloads 400-800 KB instead of 5-15 MB. ✅ Below-fold images load as user scrolls. ✅ Fast FCP, fast LCP, fast Time to Interactive.
✅ Lazy-load iframes
The heaviest elements benefit most.
<!-- YouTube embed below the fold --> <iframe src="https://www.youtube.com/embed/VIDEO_ID" width="560" height="315" loading="lazy" title="Product demo" allow="accelerometer; encrypted-media; picture-in-picture"> </iframe> <!-- Map embed below the fold --> <iframe src="https://www.google.com/maps/embed?pb=..." width="600" height="400" loading="lazy" title="Office location"> </iframe>
YouTube embed: ~500 KB to 1.5 MB (network + scripts) Google Maps: ~300 KB to 1 MB Generic widget: varies Without loading="lazy": all iframes load on first paint. With loading="lazy": only load when user scrolls near. On a page with 3-5 embeds, this saves 2-5 MB and 1-3 seconds of load time. ⚠️ Always add title to iframe (accessibility).
Don't lazy-load the hero image. This is the most common loading="lazy" mistake — add it everywhere, "for speed," and the hero takes an extra 500ms to load. LCP (Largest Contentful Paint) is often the hero image, and it's a Core Web Vital. Lazy-loading it delays LCP by the full download time, which can hurt Page Experience rankings. The hero should always be eager. Below-the-fold content should be lazy. The rule is not "lazy everywhere" — it's "lazy where it helps."
⚠️ Common mistakes
The lazy-loading mistakes that cost real time.
Delays LCP. Fix: leave above-the-fold images eager.
Delays visual completion. Fix: eager for above-the-fold UI.
width and heightLayout shifts as lazy images load. Fix: set dimensions so the browser reserves space.
The primary map or video above the fold. Fix: leave eager if it's part of first paint.
The user scrolls fast, the image isn't loaded yet. Fix: combine with a low-quality placeholder (LQIP) or blur-up effect.
The user prints the page, images haven't loaded. Fix: JS can trigger load before print.
data-src needs JS to swap; loading=lazy is native. Fix: use loading=lazy; data-src is the old pattern.
❓ Frequently asked
What does loading=lazy do?
loading=lazy tells the browser to defer loading an image or iframe until it's near the viewport. The browser waits until the element is within a scroll distance (usually 300-800px) of the visible area, then downloads it. Images above the fold load normally. Images below the fold load as the user scrolls. The benefit is a faster initial page load — fewer bytes downloaded, less bandwidth used, faster First Contentful Paint. No JavaScript, no library, no IntersectionObserver code.
Should I use loading=lazy on all images?
No. Only on images below the fold. Images visible on first paint (the hero image, the logo, above-the-fold product photos) must load eagerly — loading=lazy on those delays the visual completion and hurts LCP (Largest Contentful Paint). A common mistake is adding loading=lazy everywhere, which delays the hero image and slows the page. The rule: eager for above-the-fold, lazy for below-the-fold. When in doubt, eager — the bandwidth cost is less than the LCP penalty.
Does loading=lazy work on iframes?
Yes. loading=lazy works on iframe as well as img. This is particularly useful for embedded third-party content — YouTube videos, maps, social embeds — which are often the heaviest elements on the page. An iframe with loading=lazy only loads when the user scrolls near it, saving hundreds of kilobytes per embed. Combine with a poster image or a placeholder for the best UX — the user sees something immediately while the iframe loads on demand.
What browsers support loading=lazy?
All modern browsers since 2020: Chrome 77+, Firefox 75+, Safari 16.4+, Edge 79+. Older browsers ignore the attribute and load the image eagerly — which is fine, just less optimal. There is no risk of the image not loading. The fallback behavior is simply 'load it now,' which is what you'd get without the attribute. No JavaScript polyfill needed. If you must support very old browsers, they degrade gracefully to eager loading.
How far from the viewport does lazy loading trigger?
Browsers use different thresholds, typically between 300px and 800px. Chrome fires about 1250px before the viewport on fast connections, less on slow ones. Safari fires later — around 300px. The exact value is browser-specific and not configurable via HTML. For most pages, the difference is not visible to the user — the image loads before it scrolls into view. If you need precise control over the threshold, use IntersectionObserver with JavaScript instead.
Does loading=lazy help SEO?
Indirectly. Lazy loading improves page speed — faster First Contentful Paint, lower Total Blocking Time, and better LCP if used correctly. Google uses these metrics in the Page Experience ranking signal. But loading=lazy on the wrong element (the hero image) hurts LCP and can lower rankings. The benefit is real but conditional. Use it on below-fold images and iframes to speed up the initial load, and leave above-the-fold images eager to protect LCP.