Speed: Core Web Vitals and a budget

Why:A slow site loses people before they have read the first word. Afterwards you know the three measures of speed (LCP, INP and CLS) and their thresholds, you can find the main element of your page, fix the usual causes of slow loading and jumping layouts, and write down a budget: how many kilobytes and requests your page is allowed.

25 minutes

Read by speech synthesis (Qwen3-TTS); the voice is not a person’s.

Core Web Vitals are three measures of page speed: LCP (main content shown), INP (response) and CLS (layout shift). A budget sets the limits in advance.

Why speed matters at all

Speed is respect for other people’s time. Someone opens your page on a phone on the subway, the signal comes and goes, and a white screen that lasts too long reads as “the site is broken.” They don’t wait to find out. They press back and go to the next link in the results. You will never see this person in your inquiries: they never reached the first word.

At the start of the course we set ourselves a bar: the main content of the course site shows in under 2.5 seconds on an average phone on a 4G network. The number isn’t invented for the course. It is the “good” threshold of the Core Web Vitals, a set of measures that Google published to describe how a page feels to real people, and that everyone now uses, from search engines to developers. We talked about the search side of this in the part on SEO. Here the subject is how to measure it and fix it.

Three measures

Today the Core Web Vitals are three numbers. Each answers a question a person has:

  • LCP (Largest Contentful Paint). The question: can I see the main thing yet? It is the time until the biggest element of the first screen appeared, usually the main picture or a large heading with a paragraph. Good: up to 2.5 s. Poor: over 4 s.
  • INP (Interaction to Next Paint). The question: does the page hear me? A person taps, and this is the time until the screen answers. The slowest of the significant interactions in a visit counts. Good: up to 200 ms. Poor: over 500 ms. Since 2024 it has replaced the older FID.
  • CLS (Cumulative Layout Shift). The question: does the page stay put? It is the sum of unexpected shifts: a banner slid in at the top, or an image loaded and pushed the text aside. Good: up to 0.1. Poor: over 0.25. CLS has no units: it is the fraction of the screen that moved, multiplied by how far it moved.

The thresholds apply to the 75th percentile of real visits. For a page to count as good, it must be fast not on average but for three people out of four, including those with an old phone and a bad connection. That is why you test under slow conditions and not on your own fast laptop.

Check yourself: which measure answers the question “does the page stay put?”

CLS, the cumulative layout shift. LCP tells you when the main thing is visible, and INP tells you how quickly the page answers.

Lab data and field data

Speed is measured in two ways, and the numbers differ.

A lab measurement is one run under set conditions. This is how Lighthouse works (it is built into Chrome’s developer tools and runs inside PageSpeed Insights): it simulates a slow phone and a network of about 1.6 Mbit/s with a delay of around 150 ms. The plus: you can repeat it and hunt for the cause by changing one thing at a time. The minus: it is a single run on an imaginary network.

Field data is measurements from real visitors. Chrome keeps a report on real users, which PageSpeed Insights shows for sites with enough visitors. Analytics tools often have something similar, with page load times for real visits. The plus: this is the truth about people. The minus: the data arrives weeks later, and it doesn’t say what is wrong.

A working routine: find the problem in field data, find the cause in the lab, fix it, and confirm with field data some time later. A small site with no traffic can make do with the lab: fix the obvious, and don’t agonize over how it looks to real people.

The main element (LCP): what it is and how to speed it up

Open any page in PageSpeed Insights and find the line “Largest Contentful Paint element” in the report. It names the element. Most often it is an image on the first screen. The LCP time has four parts: the server’s response, the delay before the main resource starts loading, the loading itself, and the delay before it is shown. You treat each in turn:

  1. The server’s response: a CDN, a cache, fast hosting (we covered these in the part on infrastructure).
  2. The start delay: don’t hide the main picture behind a script or a style, don’t put loading="lazy" on it, and give the browser the hint fetchpriority="high" that this one is to be fetched first.
  3. The loading: compress the picture, use modern formats (WebP, AVIF), and serve the right size through srcset and sizes. Why send a phone a picture 3,000 pixels wide?
  4. The showing: don’t block rendering with extra styles and scripts in the head, use defer for scripts, and use font-display: swap for fonts so the text appears straight away in a fallback font.

The rule from the lesson on images stands: lazy only for images below the first screen, so that they don’t take network capacity from the main one.

Check yourself: why is loading=lazy harmful for the main picture?

The browser postpones loading such an image until it has laid out the page and worked out that the image is in view. You are slowing down the very thing that should load first.

Layout jumps (CLS)

You know where jumps come from from the lesson on rendering: the browser didn’t know how much room something still loading would take. The cure is to tell it in advance.

  • Image sizes. The width and height attributes in the markup: the browser reserves room by the aspect ratio even before the image arrives. aspect-ratio in CSS works too.
  • Room for inserts: a cookie banner, a chat, an ad, a video. Give the container a height, and don’t insert content above what is already shown.
  • Fonts: while a font loads, the browser shows a fallback and then swaps, and lines can re-flow. Hosting your own font, choosing a close fallback and loading only the characters you need all help.
  • Animations with transform and opacity, not by changing top, width and height.

Response (INP)

A page answers a tap when the browser’s main thread is free. If it is busy with a heavy script at that moment, the tap waits. The usual culprits are third-party widgets: chats, counters, social feeds and maps, which pull in hundreds of kilobytes of code. What you can do:

  • remove what nobody uses, and don’t add things “just in case”;
  • load the chat and maps after the first tap or on a button press, not together with the page;
  • load scripts with defer, split long tasks and keep event handlers short;
  • remember progressive enhancement (the part on JavaScript): a page that works without the script doesn’t depend on whether the script managed to load.

A performance budget

Speed gets worse a bit at a time: a counter was added, then a chat, then a pretty slider, and each step is “hardly noticeable.” A performance budget is a limit set in advance that isn’t up for discussion at the moment of temptation: “the page weighs no more than 500 KB, makes no more than 15 requests, and shows the main thing within 2.5 seconds on a slow network.” Then a new feature isn’t simply “added.” It has to displace something, or justify why the budget should rise.

How to choose a number. As a rough guide, a slow network delivers about 200 KB a second. So everything the main thing needs (the HTML, the styles, the main picture) has to fit into about 200 to 300 KB to show up in a couple of seconds. The budget for the whole page is bigger, because the rest loads after the first screen. Your numbers depend on your audience: stricter for a site read on the subway over a mobile network, looser for an internal tool on an office network.

A budget is also a check. Lighthouse CI runs a measurement on every deploy and fails when the page goes over the limit; this is exactly how this textbook is checked (at the start of the course we named the limit: the first route under 150 KB of compressed JavaScript). For a small project it is enough to write the number down and open PageSpeed Insights once a month.

Play with the diagram: switch fixes on and see which one moves what. Notice that someone else’s chat is the heaviest thing on the page: even deferred, it weighs 250 KB, and the page’s total weight can’t come down without dealing with it.

Load waterfall: what drags the page down

This is a model of one landing page on a slow mobile network (200 KB/s). Switch fixes on one at a time and see which one moves which measure. The numbers are for teaching: real ones come from Lighthouse and from real visits.

LCP: when the main element is visible 8.1 s ✕ poor good up to 2.5 s, poor over 4 s
INP: how fast the page responds 510 ms ✕ poor good up to 200 ms, poor over 500 ms
CLS: how much the layout jumps 0.34 ✕ poor good up to 0.1, poor over 0.25

Page weight 1745 KB against a budget of 800 KB: over by 945 KB. Requests 10 against a budget of 15: within budget. Fixes switched on: 0 of 7.

Text alternative: with no fixes the page loads about 900 KB of main picture, lazily, a big script and a third-party chat together with the first screen: LCP about 8 s, INP about 500 ms, CLS about 0.3. A compressed picture with high priority, image sizes, defer, a lighter script, the chat after a tap and a font with swap bring all three measures into the green zone.

Practice

You are in the era of 2019: sites have grown heavy and speed has started to be measured in numbers. You get a page with the usual ailments: a main picture loaded lazily, images without sizes, a script without defer, and a font that holds up the text. Fix them and write a speed note: which section of the brief opens first, what the main element in it is, and the budget in numbers.

The check reads markup and text. It can’t show you a real load time, so come back to the page after the lesson: open it on a phone and in PageSpeed Insights, and compare it with the budget.

If you build your site in a site builder (Wix, Squarespace, WordPress with a theme), you have no access to the markup, but you do have settings: turn on compression and modern image formats, lazy loading for images below the first screen, and keep plugins and widgets to a minimum.

What used to be different

In the 2000s and 2010s a “fast site” meant a site without heavy Flash. Speed was measured with a stopwatch and a feeling, and giant background images and a dozen included libraries were normal, because the developer had a fast laptop and a wired connection. Now most people arrive from a phone, and Core Web Vitals gave everyone a common language: three numbers, three thresholds, one tool. They are still changing: INP replaced FID in 2024, and thresholds get revised too. Check the current values on web.dev.

Practice

Preparing your page…

Test

Question 1 of 6

Match each measure with what it measures

Find the match for each item.

Cards

These cards go into your review once you finish the lesson.

  • Name the three Core Web Vitals and the “good” thresholds

    Answer

    LCP up to 2.5 s (when the main element is visible), INP up to 200 ms (response), CLS up to 0.1 (layout shifts). Scored at the 75th percentile of real visits.

  • How do you speed up LCP?

    Answer

    Find the LCP element, compress it and pick the right size, never lazy-load it, give it fetchpriority=high, don’t block rendering with scripts and styles, and serve it through a CDN.

  • How do you get rid of layout jumps?

    Answer

    Give images a width and a height (or aspect-ratio), reserve space for banners and inserts, and never insert content above what is already shown.

  • What ruins INP, and how do you cure it?

    Answer

    Long tasks on the main thread: heavy scripts and third-party widgets. Ship less code, use defer, load chat and analytics late, and keep event handlers short.

  • What is a performance budget?

    Answer

    A limit you set in advance: page weight, number of requests, time to show. It turns “it would be nice to be faster” into a condition you can check.

Sources

Next

You now know: core Web Vitals, the performance budget.