Skip to content

How images hurt LCP (and how to fix)

Images are the LCP element on roughly 75% of pages. When LCP is slow, the image is almost always the reason. Here's how images specifically cause slow LCP, and the fixes that move the number.

Why images dominate LCP

The biggest visible element in the viewport is usually a hero image, a product photo, or a blog post header. Chrome picks whatever has the largest rendered area as the LCP candidate. That's usually the image.

LCP for an image fires when all three of these are done:

  1. The image URL is known (HTML is parsed)
  2. The image bytes have arrived
  3. The image is decoded and painted

Each step can be slow in its own way.

The three most common image-LCP problems

Problem 1: The image is huge

A 3MB JPEG hero image downloads at roughly 250–500 KB/sec on a flaky mobile connection — that's 6–12 seconds before the image has even finished downloading.

Fix: convert to AVIF (roughly 50% smaller than JPEG at same quality) or WebP (roughly 30% smaller). Serve responsive sizes with <img srcset> so a mobile device doesn't download the desktop version. A 150KB AVIF hero loads in under a second almost everywhere.

Problem 2: The browser doesn't prioritize it

By default, the browser fetches resources in the order they appear in the HTML. If your hero image is loaded via CSS background-image after a bunch of other resources, it won't start downloading until those finish.

Fix:

  • Load the hero as <img> in HTML, not a CSS background
  • Add fetchpriority="high" to the <img>
  • Add <link rel="preload" as="image" href="/hero.avif" fetchpriority="high"> in <head>
  • Do NOT add loading="lazy" to the LCP image (this is the opposite of what you want)

Problem 3: The image is lazy-loaded

Frameworks like Next.js's <Image> default to lazy-loading for off-screen images. That's correct for most images, but wrong for the LCP image.

Fix in Next.js: add priority to the LCP <Image>:

<Image src="/hero.jpg" alt="" width={1200} height={630} priority />

Fix in plain HTML: make sure the hero <img> does NOT have loading="lazy", and does have fetchpriority="high".

Other image-LCP fixes

Use modern formats everywhere. Convert at build time with sharp, or pipe through an image CDN (Vercel Image, Cloudflare Images, imgix, Imgproxy).

Size responsively. Serve a 400-wide image to a 400-wide viewport. <img srcset="x-400.jpg 400w, x-800.jpg 800w, x-1600.jpg 1600w" sizes="100vw"> lets the browser pick.

Decode async so decode doesn't block paint:

<img src="/hero.avif" decoding="async" fetchpriority="high" …>

Use explicit width and height. This doesn't directly affect LCP, but it prevents CLS and lets the browser allocate space immediately — which indirectly helps the visual impression of load speed.

Consider aspect-ratio boxes for responsive images. The browser can pre-allocate height based on width: 100%; height: auto; aspect-ratio: 3/2; without waiting for bytes.

The minimum viable checklist

For every LCP image on every page:

  • AVIF or WebP format
  • Sized responsively (srcset + sizes)
  • Under 150KB for mobile viewport
  • fetchpriority="high"
  • Not loading="lazy"
  • Explicit width and height
  • Behind a CDN

If all seven are true, image-caused LCP is under 1 second on almost any connection.

By Paulo de Vries · Published

Frequently asked questions

Why do images hurt LCP?
Because on ~75% of pages, the largest visible element IS an image. Slow image = slow LCP. Heavy, late-prioritized, or lazy-loaded hero images are the main culprit.
Should I use AVIF or WebP?
AVIF if your target audience is on modern browsers (>95% support). It is ~50% smaller than JPEG at equal quality. WebP is a safe fallback with universal support.
Should the hero image use loading="lazy"?
No. loading="lazy" is for below-the-fold images. The LCP image should use fetchpriority="high" and, ideally, also be preloaded via <link rel="preload">.

Check a site's vitals

Explore by industry

See how real-world sites in each vertical perform on Core Web Vitals.

Related guides

← All guides