Performance Is a Design Decision
LCP broken into its four parts with the proportion each contributes, INP replacing FID, and the specific design choices that decide each number.
Date
Category
Writer

On 12 March 2024 the Chrome team retired a metric. First Input Delay, which had measured only the delay before a page began responding to the first tap or click, was replaced as a Core Web Vital by Interaction to Next Paint. The announcement gave developers until 9 September 2024 to move their tooling across. INP had been introduced as an experimental metric in May 2022 and announced as a future Core Web Vital in May 2023, so the change was neither sudden nor quiet. It was still a much bigger change than it looked, because FID measured a single moment near the start of a visit and INP measures the whole visit.
I mention the date because it marks the point at which the performance conversation stopped being something a designer could hand entirely to an engineer. LCP is about what you chose to put at the top of the page. CLS is about whether you reserved room for the things you knew were coming. INP is about how much work happens when someone touches the thing you drew. None of those are build configuration. They are layout decisions with a stopwatch attached.
The three numbers, precisely
The thresholds are published by Google and they are not approximate. A page is measured at the 75th percentile of page loads, segmented across mobile and desktop, which means a quarter of your visitors can be having a worse time than the number suggests.
Metric | Good | Needs improvement | Poor | Design decision most responsible |
|---|---|---|---|---|
Largest Contentful Paint | 2.5 seconds or less | 2.5 to 4.0 seconds | Over 4.0 seconds | What you chose as the hero, and how it is delivered |
Cumulative Layout Shift | 0.1 or less | Between 0.1 and 0.25 | Over 0.25 | Whether the layout reserves space for late content |
Interaction to Next Paint | 200 ms or less | 201 to 500 ms | Over 500 ms | How much the interface redraws on a single tap |
LCP, in Google's own words, reports the render time of the largest image, text block, or video visible in the viewport, relative to when the user first navigated to the page. The candidate set is narrow and worth memorising, because it tells you exactly which element on your design is being timed: img elements, image elements inside an svg, video elements (the poster image or first frame), any element with a CSS background image loaded through url(), and block-level elements containing text. Elements at zero opacity are excluded, as are elements covering the full viewport, which the browser treats as backgrounds.
So the LCP element is, almost always, the thing you spent the most time art-directing.
The hero is the metric
The HTTP Archive's 2024 Web Almanac found that images accounted for 73.3% of LCP elements on mobile and 83.3% on desktop. Text made up 26.3% and 16.3% respectively. That single statistic reframes the whole problem: in three quarters of cases, the number Google grades you on is the load time of one picture that a designer chose.
Google breaks LCP into four subparts, and gives rough proportions for a typical page:
Note where a designer's decisions land. Resource load duration is file size and format, which is the difference between a 1.4 MB full-bleed photograph and a 180 KB one. Resource load delay is discoverability: if the hero is a CSS background image, or is injected by a component that only runs after JavaScript has parsed, the browser cannot start the download until late. The Almanac found that 35% of mobile pages have an LCP element that is not statically discoverable in the HTML.
Two pieces of guidance from the Chrome team are blunt enough to quote. The first: Never lazy-load your LCP image, as that will always lead to unnecessary resource load delay. The Almanac found that 16% of mobile pages were still lazy-loading their LCP image in 2024, which was an improvement on 18% in 2022 but not much of one. The second concerns the fetchpriority attribute, which climbed from being used on 0.03% of mobile pages in 2022 to 15% in 2024: setting a high priority on more than one or two images makes priority setting unhelpful. Priority is a ranking, not a blessing. If a designer asks for six images above the fold and all six get marked high, none of them are.
A hero image is not a decoration that happens to have a file size. On three pages in four, it is the metric.
Fonts, and the second you cannot see
The font-loading problem has two failure modes, both of which have been named since long before Core Web Vitals existed. A flash of invisible text happens when the browser holds back rendering while a web font downloads. A flash of unstyled text happens when the browser renders a fallback immediately and swaps in the real font later. The CSS font-display descriptor chooses which one you get, by setting the length of two periods. During the block period, per MDN, an element using the font must render an invisible fallback font face. During the swap period, it renders a visible fallback and swaps when the font arrives.
font-display | Block period | Swap period | What the user sees |
|---|---|---|---|
auto | Defined by the browser | Defined by the browser | Unpredictable across engines |
block | 2 to 3 seconds | Infinite | Invisible text, then the web font |
swap | 0 ms | Infinite | Fallback immediately, then a reflow |
fallback | 100 ms | 3 seconds | Brief blank, fallback, late fonts abandoned |
optional | 100 ms | None | Brief blank, then fallback for this visit |
Both failure modes damage a metric, and they damage different ones. block hurts LCP whenever the largest element is text, which is a quarter of mobile pages. swap protects LCP and then hurts CLS, because the fallback and the web font almost never occupy the same space, and every line of text moves when the swap happens.
The way out is not to pick a side. It is to make the fallback and the web font take up the same room. CSS gives you four descriptors for this: size-adjust, which the Chrome team describes as a global glyph adjustment for the font face, plus ascent-override, descent-override and line-gap-override, which set the height above the baseline, the height below it, and the recommended line gap. Declare a local fallback with those metrics tuned to your web font and the swap becomes, in the team's phrase, a seamless swap.
The percentages above are illustrative, not universal. They have to be measured against the specific pair of fonts, and Chrome's guidance points at calculator tools that generate the adjusted @font-face block for a given target. What matters for a designer is the principle: a typeface choice is a layout-stability choice, and the number of weights you specify is a download budget.
Space you did not reserve
CLS has a formula, and it is short enough that there is no excuse for treating it as a black box.
Read the impact fraction again. It is an area measure. A thin notification bar that pushes the page down by 60 pixels scores badly not because 60 pixels is far, but because every visible element below it counts as unstable. This is why cookie banners, promotional strips and late-arriving alerts are so expensive: they move the entire viewport.
Google's list of common causes is short and every item on it is a design artefact rather than a bug: images or videos with unknown dimensions, fonts that render larger or smaller than their fallbacks, third-party ads or widgets that resize themselves, resources that load asynchronously, and DOM elements added dynamically. The fix, in each case, is to reserve the space. Width and height attributes on media, from which modern browsers compute an aspect ratio automatically. CSS aspect-ratio where the dimensions are fluid. A min-height on the slot where an ad or an embed will arrive, sized to what you expect.
Two details are worth knowing because they change what you are allowed to design. First, layout shifts that occur within 500 milliseconds of a user input are not counted. An accordion that opens when someone clicks it is free. An accordion that opens by itself is not. Second, composited animations using translate cannot affect other elements, so they do not count towards CLS at all, whereas animating top, left, box-shadow or box-sizing does. The same visual move is either free or costly depending on which property carries it.
What INP actually measures, and why motion is implicated
INP watches clicks, taps and key presses. Scrolling, hovering and zooming are excluded. For each qualifying interaction it measures three phases:
Most discussion of INP concentrates on the middle phase, because that is where JavaScript lives. Designers should pay more attention to the third. Presentation delay is rendering work, and rendering work scales with how much of the page has to be recalculated and repainted. The Chrome team is direct about this: large DOMs do require more work to render than small DOMs, and the problem shows up in response to a user interaction, where a large DOM can cause rendering updates to be very expensive.
An interface that changes one button's colour on tap is cheap. An interface where tapping a filter chip re-lays out a grid of 400 cards, each with its own shadow and hover transition, is not. The CSS property content-visibility exists partly for this, letting the browser skip rendering for elements that are not near the viewport.
Above-the-fold motion cuts both ways here. A running animation competes for the main thread during exactly the window when a user is most likely to make their first interaction, so it inflates input delay. And an autoplaying hero video or a carousel that advances on a timer is both a large LCP resource and a source of layout shift if its container is not sized. The Almanac's figures show INP is already the healthiest of the three on desktop at 97% good, but mobile sits at 74%, which is where the underpowered devices are.
Where the numbers actually sit
Measure | Mobile origins rated good | Desktop origins rated good |
|---|---|---|
Largest Contentful Paint | 59% | 72% |
Cumulative Layout Shift | 79% | 72% |
Interaction to Next Paint | 74% | 97% |
All three Core Web Vitals | 43% | 54% |
Fewer than half of mobile origins pass all three. That is the real state of the web in 2024, measured across the whole HTTP Archive crawl rather than across the sort of sites that write about performance.
What I got wrong
For a long time I treated CLS as a development concern and LCP as a compression concern, and I argued about both after the design was signed off. That order is backwards, and the font case is the clearest proof. By the time a build engineer is looking at font-display, the number of weights, the choice of typeface and the size of the display setting are already fixed, and all three of those are what determine whether any value of font-display can produce a good result. The same is true of the hero. Compression can take a photograph from 1.4 MB to 400 KB. Only a designer can decide that the page opens with type instead.
There is one thing I still cannot answer with evidence. Google publishes the thresholds and the percentile, but I have not found a primary source that explains why 2.5 seconds rather than 2.2 or 3.0, beyond the general statement that the thresholds are set so that a good score represents a good experience. The numbers are stable, widely enforced and worth designing to. They are also, as far as I can tell from the public documentation, conventions rather than derivations.
Sources
Google, "Web Vitals", web.dev. Definitions, thresholds and the 75th percentile rule for LCP, CLS and INP. web.dev/articles/vitals
Google, "Interaction to Next Paint (INP) becomes a Core Web Vital on March 12", web.dev blog, 12 March 2024. Transition dates, including the 9 September 2024 deadline for CrUX and PageSpeed Insights API users. web.dev/blog/inp-cwv-launch
Google, "Largest Contentful Paint (LCP)", web.dev. LCP definition, candidate element types, thresholds. web.dev/articles/lcp
Google, "Cumulative Layout Shift (CLS)", web.dev. Layout shift score formula, session window definition, thresholds, common causes. web.dev/articles/cls
Google, "Interaction to Next Paint (INP)", web.dev. Interaction types counted, the three phases of interaction latency, reporting methodology. web.dev/articles/inp
Google, "Optimize Largest Contentful Paint", web.dev. The four LCP subparts and their typical proportions, lazy-loading and fetchpriority guidance. web.dev/articles/optimize-lcp
Google, "Optimize Cumulative Layout Shift", web.dev. Reserving space, aspect-ratio, the 500 ms user-input window, composited transform animations. web.dev/articles/optimize-cls
Google, "Optimize Interaction to Next Paint", web.dev. Rendering cost, DOM size, content-visibility, layout thrashing. web.dev/articles/optimize-inp
Google, "Best practices for fonts", web.dev. The font-display block and swap period table. web.dev/articles/font-best-practices
Google, "Improved font fallbacks", web.dev. size-adjust, ascent-override, descent-override and line-gap-override. web.dev/articles/css-size-adjust
Mozilla, "font-display", MDN Web Docs. Font block period, font swap period and font failure period definitions. developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display
HTTP Archive, "Performance", The Web Almanac 2024. Origin-level Core Web Vitals pass rates, LCP element content types, lazy-loaded LCP images, fetchpriority adoption. almanac.httparchive.org/en/2024/performance
Related reading
Latest Articles.
© Moc Mallen Studio
Thoughts, ideas, and perspectives on design, simplicity, and creative process.

