How to lower LCP.
LCP is the time at which a page’s largest content element in the viewport is painted, and Google counts under 2.5 seconds as good.
The metric tries to capture the moment the user says “the page is here.” It measures not when the page’s first pixel painted but when its REAL content appeared — because for the user, the page arriving means the thing they will read arriving.
The measured element is usually either an image or a block of text. Which element is the LCP element varies by page, and the first job is finding it — the browser developer tools mark it directly in the performance panel. Optimizing the wrong element is the most common and most time-wasting mistake.
LCP is made of four parts
To lower the time, you first need to know where it goes. Google’s own breakdown defines four phases, and each phase has its own treatment.
- Time to first byte — how long did the server take to send the first response? Hosting, cache and server work.
- Resource load delay — when did the browser discover the LCP resource and start requesting it? A discovery problem.
- Resource load duration — how long did the resource itself take to download? A size and format problem.
- Element render delay — after the resource arrived, how long until it painted? A render-blocker problem.
This breakdown speeds up the diagnosis. If the time accumulates in the first phase, look at the server side; in the second, at the discovery chain; in the third, at size; in the fourth, at render-blocking resources. The work for the four is entirely different, and mixing them up means wasted effort.
Discovery delay: the most overlooked
The second phase is in practice the most frequent culprit and the least known. The problem: the browser starts requesting the LCP image only when it discovers it, and with a long discovery chain it starts late. If an image is defined as a background inside the CSS, the browser must first download and parse the HTML, then the CSS — only then does it learn the image exists.
The same problem is worse with images inserted by JavaScript: the resource is unknown until the script downloads and runs. Carousel and slider components are weak for LCP for exactly this reason — the first frame is usually placed by a script.
The fix is having the LCP resource appear directly in the HTML that comes from the server. As an image tag, not as a background. The browser’s preload scanner then discovers it while parsing the HTML and starts requesting it immediately.
The second tool for speeding up discovery is the preload hint: the browser can be told “download this resource with priority.” But this tool wants care — prioritizing everything yields the same result as prioritizing nothing, and it can slow down the real LCP resource.
Load duration: size and format
The third phase is the most concrete and usually where the biggest win comes from. The size of a hero image determines LCP directly, and on most sites that image arrives far larger than needed.
- Use modern formats — AVIF and WebP deliver the same visual quality in a markedly smaller file.
- Serve responsive sizes — sending the desktop image to a phone is the most common waste.
- Produce at real size — there is no reason for an image shown at 800 pixels to arrive at 3000.
- Measure the compression — pick the quality setting by comparison, not by eye.
- Lazy-loading the LCP image — the most common counterproductive optimization.
The last item matters especially. Lazy loading is a win for images OUTSIDE the viewport; the LCP element is by definition inside it, and lazy-loading it delays its discovery. Applying blanket lazy loading to all images on a site directly worsens LCP.
Render delay: the blocking resources
The fourth phase is the paint waiting although the resource has arrived. The cause is almost always the same: the browser paints nothing before downloading and parsing the stylesheets. Every extra stylesheet is an extra request and an extra wait.
Exactly this was measured and closed on this site. In a mobile Lighthouse run, two separate stylesheets were blocking render: one for 821 milliseconds, the other for 221. The two files were merged into one and the comments stripped — 67.4 kilobytes of source, 12.4 kilobytes after gzip. The measured gain on the render-blocking file was 11.4 kilobytes.
The stripping was deliberately kept conservative: only comments, leading indentation and empty lines. Selectors and values were never touched, because aggressive stripping gained only 747 more bytes and carried the risk of breaking descendant-pseudo patterns. The gain and the risk were both measured and compared.
You do not risk breaking a selector for 747 bytes — the gain is measured, and so is the risk.
One last reminder: LCP is not a single number but a distribution. The value examined in field data is the 75th percentile — the time three quarters of users experience. The time you measure on your own device is a sample from the best end of that distribution and is not enough for a verdict on its own.
Common wrong optimizations
Part of the effort to lower LCP works in reverse, and because these are well-known patterns they are especially insidious. The most common is blanket lazy loading on all images: right for images outside the viewport, this setting delays discovery when applied to the LCP element and directly increases the time.
Second, putting a preload hint on everything. The hint’s job is moving one resource forward; placed on ten resources at once, none moves forward — and the real LCP resource starts competing with the others for bandwidth. The number of resources worth preloading on a page is usually one or two.
Third, making font loading blocking. Text can be an LCP element, and if nothing paints until the font arrives, the time stretches directly. The right behavior is painting immediately with the fallback font and swapping when the real one arrives — but for that swap not to produce layout shift, the fallback family must match metrically.
Fourth, ignoring third-party scripts. Analytics, chat bubbles and ad scripts appear to load after the LCP element, but they share the bandwidth and the main thread. Deferring a chat bubble gains more on most sites than stripping a stylesheet.