LCP is 4.5s. Break the LCP timeline into its sub-parts and give the optimization for each.
Decomposing LCP into TTFB, load delay, load time, and render delay — and fixing the dominant part.
LCP has four sequential sub-parts, and you optimize whichever dominates — guessing wastes effort. (1) TTFB (time to first byte): how long until the HTML starts arriving. Slow TTFB caps everything downstream. Fixes: CDN/edge caching, faster server or SSR caching, fewer redirects, early hints (103). (2) Resource load delay: the gap between TTFB and when the LCP resource STARTS downloading — usually because the browser discovered it late (it's in CSS as a background-image, or injected by JS, or behind render-blocking resources) or it was deprioritized. Fixes: make the LCP image a real <img> (discoverable by the preload scanner), preload it, set fetchpriority="high", and don't lazy-load it. (3) Resource load time: how long the LCP resource itself takes to download. Fixes: compress and right-size the image (AVIF/WebP, correct dimensions), preconnect to its origin. (4) Element render delay: the gap between the resource finishing and it actually painting — caused by render-blocking CSS/JS still pending, or the element waiting on the framework to hydrate/mount. Fixes: cut render-blocking resources (inline critical CSS, defer JS), reduce hydration cost, avoid client-side-only rendering of the hero. The workflow: in DevTools or the web-vitals attribution build, read the four sub-parts, find the biggest, and target it. Commonly the win is (2)+(3): the hero image is discovered late and unoptimized — so preload it, mark it high priority, serve a modern compressed format at the right size, and ensure nothing render-blocking sits in front of it. Also confirm the LCP element is what you think; sometimes it's a large text block gated by a web font (→ font optimization) rather than an image.
Systematically driving down a slow LCP; deciding whether the bottleneck is server, network, or render.
<!-- The 4 LCP sub-parts: TTFB | load delay | load time | render delay -->
<!-- Cut load delay: warm the connection + start the hero early -->
<link rel="preconnect" href="https://img.cdn.example">
<link rel="preload" as="image" href="https://img.cdn.example/hero.avif"
fetchpriority="high">
<!-- Cut load time + delay: real <img>, high priority, NOT lazy, right size -->
<img src="https://img.cdn.example/hero.avif"
width="1200" height="675" fetchpriority="high" alt="…">
<!-- Cut render delay: inline critical CSS, defer the rest of JS -->
<style>/* above-the-fold rules */</style>
<script src="/app.js" defer></script>