Largest Contentful Paint: make the biggest thing appear fast
Largest Contentful Paint measures one thing: how long until the largest visible element in the viewport finishes rendering. Usually that is a hero image or a headline, and it is the Core Web Vital users feel most viscerally — it is the moment the page stops looking empty. Google flags an LCP over 2.5 seconds as poor. The good news is that fixing it is not a grab-bag of tricks; it is almost always the same short story: find the LCP element, and remove everything that delays it specifically.
Step one: don’t hide the LCP image from the preloader
The browser’s preload scanner finds resources in the HTML early — but it cannot
find an image whose URL only exists in JavaScript or a CSS background-image.
So the single most common LCP bug is a hero that loads late because it was not
in the initial HTML. Put the LCP image in an <img> in the markup, tell the
browser it is high priority, and never mark it loading="lazy":
<!-- the LCP image: discoverable, high priority, eagerly loaded -->
<img src="/hero-800.jpg"
fetchpriority="high"
loading="eager"
width="800" height="450"
alt="...">
Note the explicit width/height: they reserve the box so the image does not
shift layout when it arrives — which also protects your Cumulative Layout Shift.
Step two: preload it and serve the right size
If the image is important enough to be the LCP, tell the browser to fetch it
before it finishes parsing the CSS, with a preload hint in the head. And
serve a size that fits the slot rather than a 4000px original scaled down — the
bytes you don’t send are the fastest bytes:
<link rel="preload" as="image" href="/hero-800.jpg"
imagesrcset="/hero-400.jpg 400w, /hero-800.jpg 800w"
imagesizes="(max-width: 600px) 400px, 800px">
Pair that with a modern format (AVIF/WebP) and a srcset on the <img> itself,
and the download bar — the widest one in the diagram — shrinks the most.
Step three: the render delay is the critical path again
Once the image lands fast, the remaining LCP time is render delay: the element
is downloaded but cannot paint yet because a stylesheet or a blocking script is
still holding up the first render. That is the critical rendering path from the
other posts — inline the critical CSS, defer non-essential scripts, subset the
web font so the headline is not waiting on it. The reason LCP is a satisfying
metric to optimise is that it forces you to reason about one concrete element
end to end: what is it, when is it discovered, how big is it, and what is it
waiting on to paint. The responsive-image exercise builds exactly the
srcset/sizes markup that shrinks the download bar, which is where most real
LCP wins actually come from.