Chapter 08 of 09Part 3 · Quality and launch
Website speed and Core Web Vitals explained
What makes a page feel slow, the three Core Web Vitals in plain terms, and the fixes that matter most on a small site.
8 minBy Zuzo StudioUpdated
In this chapter you will
- explain what LCP, INP and CLS measure and their targets
- tell lab data from field data and when to use each
- fix the image, script and font problems that slow small sites
Before you startThis builds on Web accessibility basics: pages everyone can use.
Website speed is not one number. A page can start drawing quickly and still feel slow, because the main image arrives late, a button ignores the first tap, or the text jumps just as you go to read it. What people notice is how fast the page feels at each of those moments. Google's Core Web Vitals turn those moments into three measurements, and once you understand them you can tell which part of a slow page to fix. This chapter explains them in plain terms, then walks through the fixes that matter most on a small site like the one you are building.
01Where the time goes
In the first chapter we followed a page from the address bar to the screen: DNS, the connection, the HTML, then the CSS, scripts and images it asks for, then style, layout and paint. Every step takes time, and a slow page is usually slow in one or two of them, not all of them.
The common causes, roughly in the order you meet them:
- A slow server. The browser can do nothing until the first bytes of HTML arrive. Static files served from a CDN, a network of servers close to the visitor, arrive quickly. A page built from a database on every request can take much longer.
- Too many bytes. Large images are the usual culprit, followed by web fonts and JavaScript.
- Render blocking files. By default the browser waits for every stylesheet in the
<head>, and for any plain<script>tag, before it draws anything. - A busy main thread. The browser's main thread runs JavaScript, works out layout and responds to taps, one job at a time. A long script holds everything else up.
Real pages carry a lot. The HTTP Archive's Web Almanac 2024 chapter on page weight found that the median mobile page made 66 requests, 22 of them for JavaScript files. A one-page site has no reason to come anywhere near that.
02Core Web Vitals: website speed in three numbers
The Web Vitals programme picks three measurements, each one standing for a different part of the experience: loading, responding and staying still.
| Metric | What it measures | Good |
|---|---|---|
| Largest Contentful Paint (LCP) | When the biggest image or block of text in view has been drawn | 2.5 seconds or less |
| Interaction to Next Paint (INP) | How quickly the page shows a response after a click, tap or key press | 200 milliseconds or less |
| Cumulative Layout Shift (CLS) | How much visible content moves around unexpectedly | 0.1 or less |
Largest Contentful Paint
LCP is the moment the main thing on the screen appears, usually the hero image or the main heading. It is a better guide than "when did the page finish loading", because people start reading long before the last file arrives. A slow LCP is almost always a late or heavy hero image, a slow server, or a heading that waits for a web font or an animation before it shows.
Interaction to Next Paint
INP watches every click, tap and key press during the visit and reports the slowest one, ignoring rare outliers. It replaced First Input Delay (FID) as a Core Web Vital in March 2024. As web.dev's guide to INP explains, FID only measured the input delay of the first interaction, while INP times every interaction from the input until the browser paints the next frame. A poor INP means the main thread is busy, usually with JavaScript, when the visitor tries to do something.
Cumulative Layout Shift
CLS adds up the unexpected jumps: an image without a set size that pushes the text down when it loads, a cookie banner that shoves the page, a font swap that reflows a paragraph. A score of 0 means nothing moved. Shifts that happen just after the visitor clicks something are expected and do not count.
03Lab data and field data
There are two ways to measure speed, and they often disagree.
Lab data comes from one test load in a controlled setting. Lighthouse, built into Chrome DevTools, loads your page on a simulated mid range phone and slower network and reports LCP, CLS and a score out of 100. It is repeatable, so it is ideal while you are building. It cannot measure INP, because nobody is clicking.
Field data comes from real visitors. Chrome collects anonymous timings from users who allow it, and tools such as PageSpeed Insights and Google Search Console show the results for sites with enough traffic. This is what Google uses, and it includes everyone's slow phones and patchy connections.
Use the lab while you work and the field once you are live. A new site with little traffic will not have field data at first, which is normal.
04The fixes that matter most on a small site
For a one-page site, four habits cover most of website speed.
Size images for the screen they are shown on
A photo straight from a phone camera can easily be several megabytes. Resize it to the largest size it is actually displayed at, save it as WebP or AVIF, and let the browser pick between sizes with srcset. Always set width and height so the browser can reserve the space before the file arrives, which keeps CLS at zero.
<img
src="studio-800.webp"
srcset="studio-800.webp 800w, studio-1600.webp 1600w"
sizes="(min-width: 60rem) 50vw, 100vw"
width="1600" height="1000"
alt="Two designers sketching a layout on a whiteboard">
Lazy load only what is below the fold
Adding loading="lazy" tells the browser to wait until an image is close to the viewport before downloading it. It saves bytes for images further down the page. web.dev's guide to browser level lazy loading is clear on the limit: use it only for images outside the initial viewport.
Keep scripts out of the way
A plain <script> in the <head> stops the browser from reading the rest of the HTML until the script has downloaded and run. Add defer and the script downloads in parallel and runs after the HTML is parsed. As progressive enhancement showed, the content should never depend on it anyway.
<link rel="stylesheet" href="styles.css">
<script src="script.js" defer></script>
The same goes for third party scripts: chat widgets, video embeds, social feeds. Each one adds requests and main thread work you do not control. Add them only when they earn their place.
Go easy on web fonts
Every font file is another download, and text that waits for its font can delay LCP. Use one or two families, only the weights you need, in WOFF2 format, and set font-display: swap so the text shows in a fallback font straight away. A system font stack costs nothing at all.
@font-face {
font-family: "Studio Sans";
src: url("studio-sans.woff2") format("woff2");
font-display: swap;
}
Motion is a common reason for an otherwise light page to fail its vitals. If you want to animate, read how to keep website animation fast first.
05Keeping a site fast after launch
Speed slips over time. A new hero video, a marketing tag, a heavier font: each looks harmless, and together they undo the work. Run Lighthouse after every notable change, and once the site has traffic, check the Core Web Vitals report in Search Console every month or so. When something fails, our Core Web Vitals checklist goes through the fixes metric by metric, in more depth than this chapter.
The next and final chapter puts your page live, which is also when field data starts to arrive: how to launch a website.
Check your understanding
3 questions
Key takeaways
- Website speed is about how fast a page feels at three moments: loading, responding and staying still.
- Good scores are LCP within 2.5 seconds, INP of 200 milliseconds or less and CLS of 0.1 or less, at the 75th percentile of real visits.
- Lighthouse gives repeatable lab data while you build; field data from real visitors is what Google uses.
- Resize images, set their width and height, and never lazy load the hero image.
- Defer scripts and keep web fonts to a minimum so the main content is never waiting on them.
Sources
- Web Vitalsweb.dev, checked
- Interaction to Next Paint (INP)web.dev, checked
- Interaction to Next Paint becomes a Core Web Vital on March 12web.dev, checked
- Browser-level image lazy loading for the webweb.dev, checked
- Web Almanac 2024: Page WeightHTTP Archive, checked