Alcott

Loading site
Skip to content

2026-09-15 · 7 min · By Alcott Dube

How to improve Largest Contentful Paint: four fixes

I diagnose slow Largest Contentful Paint by separating server response, resource discovery, download time and rendering, then fixing the part that actually delays visible content.

Four connected stone channels lead towards an illuminated plane, with one long channel delaying a red sphere.

To improve Largest Contentful Paint, identify the largest visible element and fix whichever stage delays it: the initial response, resource discovery, download or rendering. I prioritise the longest stage, then check that real-user performance reaches 2.5 seconds or less at the 75th percentile.

How to find what is slowing Largest Contentful Paint

I start by identifying the element, not by compressing every image. Largest Contentful Paint measures when the largest eligible image or text block becomes visible in the viewport. That might be a product photograph on mobile and a heading on desktop. In Chrome DevTools, I record a page load in the Performance panel, select the metric marker and inspect its associated element.

Next, I use the four-part breakdown described in web.dev’s optimisation guidance: time to first byte, resource load delay, resource load duration and element render delay. These separate waiting for the document from discovering an image, downloading it and finally painting it. For a text element without a separate content resource, the resource-loading stages do not apply in the same way.

I write down the timings before choosing a fix. Consider an illustrative page with a 3.8-second result: 0.8 seconds for the first byte, 1.6 seconds before its image request begins, 0.5 seconds downloading and 0.9 seconds before rendering. Halving the download saves only 0.25 seconds. Earlier discovery offers a much larger opportunity. The largest file is not necessarily the biggest problem.

Fix slow server response before optimising the hero

If the document arrives late, everything discovered inside it starts late too. I inspect the main document request first, including redirects, connection setup and waiting for the response. Time to first byte is not simply application execution time. A slow result needs investigation across delivery and server work, rather than an automatic decision to rewrite the backend.

For a mostly public page, I check whether the document can be cached near visitors and whether that cache actually returns hits. Personalised pages need a different decision: cache shared data or fragments without accidentally sharing private content. I also inspect redirect chains, repeated database queries and remote services that must finish before the server sends useful markup.

I avoid recommending a framework migration from one slow trace. First, I compare cached and uncached requests, then test from regions where visitors actually are. If a response waits on a recommendations service, I would consider moving that feature outside the initial rendering path. The trade-off is deliberate: the main content arrives first, while optional personalisation appears later.

A red tile sits hidden behind layered screens on one side and fully exposed on the other.
A downloaded resource can still wait behind work that prevents it from becoming visible.

Make the Largest Contentful Paint image discoverable early

A browser cannot prioritise an image it has not discovered. I look for hero images inserted after JavaScript runs, hidden behind a stylesheet background, or requested only after a component fetches data. If the main image is already known on the server, I prefer an image element with its source in the initial html. That removes an avoidable dependency.

I remove lazy loading from the likely Largest Contentful Paint image. For a prominent image that matters immediately, fetchpriority="high" can tell the browser to favour its request. It does not guarantee an instant download or compensate for late discovery. I keep that signal selective. Giving several images high priority makes them compete with the resource I actually need first.

When a background image or another late-discovered asset cannot be moved into markup, I consider preloading it. The preload must match the resource the page eventually requests. Responsive images need particular care: preloading a desktop source while the image selects a mobile candidate can waste bandwidth. I verify the network trace afterwards, looking for an earlier request without a second unnecessary download.

Reduce hero image download time without damaging quality

Once the request starts early, I check whether the transfer itself is expensive. I compare the selected image’s dimensions with its rendered size and expected pixel density. A 2,400-pixel-wide source may be wasteful in a 400-pixel slot, although a high-density screen still needs more than 400 source pixels. Responsive image candidates and accurate sizes attributes let the browser choose more appropriately.

I then compare compression levels and formats using the actual photograph or illustration. Webp or avif can reduce transfer size, but I inspect the result rather than assuming a format switch is enough. Product textures, fine lettering inside images and gradients expose different defects. A practical target is the smallest acceptable asset for that placement, not an arbitrary site-wide kilobyte limit.

I also check image caching and delivery distance. Those changes can help, but a warm browser cache can conceal a poor first visit during testing. I test cold loads as well. If the image downloads quickly but remains invisible for another second, I stop adjusting quality. web.dev explicitly distinguishes download time from render delay; shrinking bytes cannot remove the latter.

Fix render delay after the image has loaded

Render delay is where I look when the resource has arrived but the page still has not painted it. Chrome DevRel’s Performance panel documentation provides the tooling for inspecting main-thread activity around that gap. I look for long script tasks, stylesheet dependencies and visibility rules. An image waiting behind an entrance animation is a different problem from an image waiting behind JavaScript execution.

My first change is usually to remove an unnecessary gate. The main content should not need a carousel library, an analytics callback or client-side hydration to become visible when it could already exist in the document. I defer nonessential scripts and split expensive work where the trace supports it. I do not remove code simply because a bundle report labels it large.

For a text-based result, I inspect styles and font loading instead of hunting for a hero image. A font-display strategy that permits fallback text can reduce invisible text, but font substitution may change line breaks and cause layout shifts. I choose a close fallback and check both metrics. Inlining critical styles can help too, provided the extra document weight and maintenance are justified.

How to verify a Largest Contentful Paint improvement

I use repeatable lab tests to diagnose changes and field data to judge the visitor experience. In PageSpeed Insights, I check whether field results describe the requested page or fall back to the origin. I also separate mobile and desktop. web.dev defines a good result as 2.5 seconds or less at the 75th percentile, not as a favourable average.

For a before-and-after comparison, I keep the viewport, throttling settings and cache conditions consistent, and run several tests rather than trusting one. I record the element and its four timings alongside the overall result. Otherwise, a different element becoming the largest candidate can make the change hard to interpret. The point is to explain the improvement, not just capture a better score.

After release, I watch real-user measurements across the affected page types. Chrome’s public field reporting uses a rolling 28-day window, so it will not immediately reflect a deployment. Where faster feedback matters, I use the web-vitals library to collect measurements, with appropriate privacy controls. I keep the change only if the gain survives normal traffic without harming layout stability, interaction responsiveness or image quality.

Questions people ask

What is a good Largest Contentful Paint time?

web.dev sets the good threshold at 2.5 seconds or less at the 75th percentile. I assess mobile and desktop separately because a combined result can hide a slower experience.

Does lazy loading improve Largest Contentful Paint?

Not when applied to the image responsible for the metric; it can delay its request. I reserve lazy loading for images outside the initial viewport and make the main image discoverable early.

Why is Largest Contentful Paint slow with a small image?

The browser may discover it late, receive the document slowly or wait before rendering it. I inspect those delays before reducing image quality further.

Why are Lighthouse and PageSpeed Insights field results different?

Lighthouse tests one simulated load, while field results describe real visits over time. I expect differences caused by devices, networks, cache states and the reporting window, rather than treating either result as interchangeable.

Where I checked my thinking

Start a project