DomainLens

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.

Check your site before you start fixing

Run a fresh DomainLens audit and use the report as your priority list.

Run a free SEO audit

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.

The whole API
<!-- 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.

ImageloadingAlso set
Hero / LCP candidateeagerfetchpriority="high", preload
Above the fold, secondaryeagerwidth and height
Below the foldlazywidth and height
Long gallery or feedlazyConsider decoding="async"
Tracking pixellazyNothing else
CSS background imagen/aPreload 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.

  1. 1Identify the LCP element in a Lighthouse trace before changing anything.
  2. 2Confirm that element does not carry loading="lazy" — this alone fixes many regressions.
  3. 3Check that every image has explicit width and height, so deferring one does not shift the layout.
  4. 4Inspect the rendered DOM for src attributes still holding placeholders.
  5. 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.

Related resources