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:
- The image URL is known (HTML is parsed)
- The image bytes have arrived
- 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
widthandheight - Behind a CDN
If all seven are true, image-caused LCP is under 1 second on almost any connection.
By Paulo de Vries · Published