Tags: web-dev concept

Largest Contentful Paint

Date: 2026-08-16


When the biggest thing in the viewport finished rendering. Diagnosing it means splitting it into four phases and finding which one is long — because the fix for a slow server has nothing in common with the fix for a late-discovered image.


What it is

Largest Contentful Paint (LCP) measures the render time of the largest image or text block visible in the viewport, relative to when the page started loading.

Good is ≤ 2.5 seconds at the 75th percentile. See Core Web Vitals.

The element is chosen by the browser, and it changes as the page loads — the LCP candidate updates until the user first interacts. Candidates: <img>, <image> inside SVG, <video> poster frames, an element with a CSS background-image, and block-level text nodes.

The four phases

The essential diagnostic. LCP decomposes into four intervals, and the fix depends entirely on which one dominates.

│──────────│─────────────│──────────────│──────────────│
   TTFB       resource        resource        element
              load delay      load time       render delay

   server     time between    downloading     time between
   +network   TTFB and the    the resource    download and
              fetch starting                  paint
PhaseLong meansFix
TTFBSlow server, slow network, redirectsTime to First Byte, caching, CDN Caching
Load delayThe resource was discovered latePut it in markup; preload; fetchpriority
Load timeThe file is too big or the connection is slowImage Optimisation, compression
Render delaySomething blocked rendering after downloadRender-Blocking Resources, Long Tasks and Blocking

Load delay is the most commonly dominant and the most commonly misdiagnosed. Teams compress an image that was never the problem, because the browser didn’t start fetching it until 1.8 seconds in.

The ordinary causes

In rough order of how often they’re the real answer:

  • The LCP image is a CSS background-image. Not discoverable by the preload scanner, so the fetch starts only after CSS parses — see Document Parsing
  • The LCP image is lazy-loaded. loading="lazy" on the hero is a self-inflicted delay of hundreds of milliseconds. Never lazy-load anything above the fold
  • The image is injected by JavaScript — a carousel or personalisation widget. Discovery waits for a script to download, parse and execute
  • Render-blocking CSS or JS delays paint even though the image arrived
  • A web font is the LCP element’s font, and text is invisible until it loads — Font Loading
  • Slow server — the floor everything else sits on

Fixing it in order

  1. Measure the phases, don’t guess. Chrome DevTools’ Performance panel breaks LCP down; the web-vitals library exposes the same attribution in the field
  2. Make it discoverable. LCP image in the markup as <img>, with fetchpriority="high":
    <img src="/hero.avif" fetchpriority="high" width="1200" height="600" alt="…">
    Width and height also prevent the shift that would hurt Cumulative Layout Shift
  3. Remove loading="lazy" from anything in the initial viewport
  4. Preload if it genuinely can’t be in markup — Resource Hints
  5. Shrink it. Correct dimensions for the breakpoint, modern format, responsive srcset — Image Optimisation
  6. Unblock rendering — inline critical CSS, defer scripts — The Critical Rendering Path
  7. Cut TTFB — caching, CDN, faster origin

Traps

  • The LCP element differs by viewport. Mobile’s largest element is often not desktop’s. Diagnose separately
  • It differs by template. Category pages, product pages and the homepage have different LCP elements and usually different causes. Site-wide averages hide this
  • Optimising the wrong element. Check what the browser actually selected before spending a sprint on it — DevTools names it
  • Lab and field disagree. Lab runs one connection on one device; the field is your real distribution. Trust the field for whether, the lab for why — Field vs Lab Data
  • A carousel whose first slide is the LCP element makes LCP dependent on carousel initialisation, which is usually JavaScript, which is usually late

The unglamorous fact

For most retail sites the single largest LCP win is serving a correctly-sized, modern-format hero image from markup, not lazy-loaded, over a CDN. That’s four changes, none of them interesting, and they typically outperform any amount of JavaScript optimisation.