Learn
Lazy Loading Images: When It Helps and When It Costs You LCP
Lazy loading defers images until they are needed. Apply it to the one image that is needed immediately and you have delayed your own Largest Contentful Paint.
Run a fresh DomainLens audit and use the report as your priority list.
How native lazy loading works
The loading attribute tells the browser to defer an image until it approaches the viewport. It is one attribute, needs no JavaScript, and is supported everywhere that matters — which makes every script-based implementation legacy code worth deleting.
The browser decides the threshold, and it varies with connection speed: on a slow connection it starts loading earlier so the image is ready by the time it scrolls into view. You cannot tune that, and you should not want to.
<!-- Below the fold: defer it -->
<img src="/photo.jpg" alt="…" loading="lazy" width="800" height="600">
<!-- Above the fold: load immediately (the default) -->
<img src="/hero.jpg" alt="…" loading="eager" width="1600" height="900"
fetchpriority="high">
<!-- width and height are not optional: without them the
browser cannot reserve space, and the page shifts
when the image arrives. -->
Why lazy-loading the hero image is a mistake
The Largest Contentful Paint element is usually the hero image. Marking it loading="lazy" tells the browser to wait — so the browser discovers it later, requests it later, and paints it later. The metric gets measurably worse, and the change looks like an optimisation in the diff.
This happens most often when lazy loading is applied globally by a plugin or a template loop. Every image gets the attribute, including the one that must not have it.
What to do with each image
Background images set in CSS cannot be lazy-loaded with this attribute at all, because there is no img element to put it on. The browser defers them naturally until the rule applies — which is a problem in the opposite direction when the background is your LCP element, since it is discovered only after the CSS parses.
| Image | loading | Also set |
|---|---|---|
| Hero / LCP candidate | eager | fetchpriority="high", preload |
| Above the fold, secondary | eager | width and height |
| Below the fold | lazy | width and height |
| Long gallery or feed | lazy | Consider decoding="async" |
| Tracking pixel | lazy | Nothing else |
| CSS background image | n/a | Preload if it is the LCP element |
Does lazy loading affect indexing?
Native lazy loading is safe for indexing: Googlebot renders with a viewport tall enough that deferred images resolve, and the src is present in the HTML either way.
JavaScript implementations are where content goes missing. The old pattern of putting the real URL in data-src and swapping it on scroll leaves an img whose src is a placeholder — and if the script does not run during rendering, that placeholder is what gets indexed. Every image on the page becomes invisible to image search.
- Keep the real URL in src and use the loading attribute; never rely on a scroll handler.
- If you must use a script, provide a noscript fallback with the real image.
- Check the rendered HTML rather than the source to confirm what Google receives.
- Never lazy-load an image that is also referenced in structured data.
Verifying it did what you expected
Layout shift is the quiet cost here: an image without dimensions reserves no space, so deferring it guarantees the content below jumps when it arrives. See what LCP measures for the metric and image SEO for the rest of the image work.
- 1Identify the LCP element in a Lighthouse trace before changing anything.
- 2Confirm that element does not carry loading="lazy" — this alone fixes many regressions.
- 3Check that every image has explicit width and height, so deferring one does not shift the layout.
- 4Inspect the rendered DOM for src attributes still holding placeholders.
- 5Re-measure LCP after the change; a lazy-loading edit that does not move it was cosmetic.
How DomainLens contributes
DomainLens reports lazy-loading usage alongside the LCP element it measured, which is how a hero image marked lazy shows up as a cause rather than a coincidence. For the broader picture see the Core Web Vitals guide .
- Does lazy loading hurt SEO?
- Native lazy loading does not — Google renders deferred images fine. JavaScript implementations that leave a placeholder in src do, because that placeholder is what gets indexed.
- Should I lazy-load every image?
- No. Images above the fold, and the LCP element in particular, should load eagerly. A blanket rule makes LCP worse.
- Can I lazy-load CSS background images?
- Not with the loading attribute, since there is no img element. They are deferred naturally, which is a problem when the background is your LCP element — preload it instead.
- Do I still need a lazy-loading library?
- No. Native support is universal in current browsers, and a library now adds JavaScript that delays the very thing it was meant to speed up.