The Build Ledger Search articles
Back to articles

Why Largest Contentful Paint Regresses After a Simple Hero Image

Image priority, layout stability, request waterfalls, and font loading can turn a harmless component into the slowest part of the page.

Largest Contentful Paint often regresses after a “simple” hero image because the browser is not just downloading a file. It is discovering the resource, parsing CSS, reserving layout space, loading fonts, running JavaScript, and deciding which visible element counts as the LCP candidate.

A hero can look harmless in the design review and still add a request waterfall to the first viewport.

First identify the actual LCP element

Do not assume the hero image is the candidate. In Chrome DevTools Performance, inspect the LCP event and note the element:

LCP candidate: h1.hero-title
Time: 2.8s
Observation: custom font delayed final text paint

or:

LCP candidate: img.hero-image
Time: 3.4s
Observation: image discovered after CSS background loaded

The fix depends on the candidate. Font delay and late image discovery are different problems.

Avoid hiding critical images in CSS

A common regression looks like this:

.hero {
  background-image: url("/images/home-hero.avif");
}

The browser may need HTML, CSS, and style calculation before it discovers the image. If the image is meaningful and above the fold, put it in markup with dimensions:

<img
  src="/images/home-hero-1280.avif"
  srcset="/images/home-hero-640.avif 640w, /images/home-hero-1280.avif 1280w"
  sizes="(max-width: 768px) 100vw, 50vw"
  width="1280"
  height="720"
  alt="Dashboard preview showing release health metrics"
  fetchpriority="high"
/>

Do not use fetchpriority="high" everywhere. Use it for the one image that is truly critical.

Reserve the box before the file arrives

If the browser does not know the image dimensions, layout can shift after the image loads. That shift can delay the final stable candidate and make the page feel slower.

Use width and height attributes, CSS aspect-ratio, or a framework image component that reserves the correct slot. Avoid a hero wrapper whose height depends on client JavaScript.

.hero-media {
  aspect-ratio: 16 / 9;
  overflow: hidden;
}

.hero-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

Match bytes to the rendered slot

Serving a 2400 px desktop image to a 390 px mobile viewport is an easy way to lose LCP. Check the rendered slot size and the downloaded asset size in the network panel.

For screenshots and UI images, compression choices differ from photographs. A crisp PNG may be too large; an over-compressed WebP may blur text. Measure the actual candidate, not just the extension.

Watch for client-rendered heroes

Hero sections often regress when moved into a client component. The page may wait for JavaScript before meaningful HTML, image discovery, or layout.

If the hero is mostly static, keep it server-rendered. Hydrate only the small interactive part:

<HeroCopy />
<HeroImage />
<ClientOnlySignupForm />

The page should not need a client bundle to reveal the largest above-the-fold element.

Compare traces, not just scores

After the fix, compare before and after traces:

Before: hero image discovered at 1.4s, LCP at 3.4s
After: hero image discovered at 0.25s, LCP at 1.9s

The improvement should be visible as earlier discovery, fewer blocking requests, smaller transfer size, or a stable candidate. If the number improves but the trace still has a fragile waterfall, the next design change will probably break it again.