# Core Web Vitals

## Hvad det er

Googles dokumentation på web.dev udvælger tre målinger fra det bredere Web
Vitals-program og kalder dem centrale (core): Largest Contentful Paint for
indlæsning, Interaction to Next Paint for respons og Cumulative Layout Shift for
visuel stabilitet. Hver af dem beskriver noget, en besøgende lægger mærke til,
gælder for alle sider og kan måles i felten, i de besøgendes egne browsere.

Largest Contentful Paint (LCP) er tiden fra navigationen begynder, til det
største synlige billede, tekstblok eller video i viewporten er tegnet. Den er
god ved 2,5 sekunder eller mindre og dårlig over 4 sekunder.

Interaction to Next Paint (INP) følger hvert klik, tryk og tastetryk under et
besøg og tager hele den ventetid, den besøgende oplever: forsinkelsen, før
hændelseshåndteringen går i gang, den tid, håndteringen kører, og tiden, til
næste billede er tegnet. Sidens INP er den længste af dem, men for hver 50
interaktioner springes én afviger over. Rulning, hover og zoom tæller ikke med.
Den er god ved 200 millisekunder eller mindre og dårlig over 500. INP afløste
First Input Delay den 12. marts 2024 efter at være blevet indført som
eksperimentel måling i maj 2022; First Input Delay målte kun forsinkelsen, før
den første interaktions håndtering begyndte.

Cumulative Layout Shift (CLS) giver point for synlige elementer, der flytter
sig, uden at nogen har bedt om det. Hvert skift scorer den andel af viewporten,
de flyttede elementer dækker, ganget med, hvor langt de flytter sig. Skift med
under et sekunds mellemrum, højst fem sekunder i alt, udgør et sessionsvindue,
og CLS er summen af det værste vindue. Skift inden for 500 millisekunder efter
et tryk, klik eller tastetryk tilgives; rulning og træk undskylder intet. Den er
god ved 0,1 eller mindre og dårlig over 0,25.

Dommen læses ved 75-percentilen af sidevisningerne, hver for sig for mobil og
desktop, og en side består kun, når alle tre er gode der. En grænse for »god«
blev kun godtaget, hvis mindst en tiendedel af alle origins allerede nåede den.

Nedenunder ligger browsergrænseflader med egne specifikationer, Largest
Contentful Paint-, Layout Instability- og Event Timing-API'erne, og få linjer
viser råmaterialet til CLS på en hvilken som helst side:

```js
new PerformanceObserver((list) => {
    for (const shift of list.getEntries()) {
        if (!shift.hadRecentInput) console.log(shift.value, shift.sources);
    }
}).observe({ type: "layout-shift", buffered: true });
```

Det logger de enkelte skift, ikke selve målingen; web.dev henviser til
biblioteket `web-vitals` for de tre, sådan som Googles værktøjer rapporterer
dem.

Begrebet forveksles let med Lighthouses performance-score, som kommer fra én
simuleret indlæsning i et laboratorium uden nogen besøgende; vurderingen af Core
Web Vitals beskriver rigtige besøg ved 75-percentilen, og en side kan klare sig
godt i den ene og dårligt i den anden.

## Hvorfor det betyder noget

Definitionerne siger intet om, hvor tallene kommer fra, og det er netop den
beslutning, et site skal træffe: styre efter proxymålinger fra laboratoriet
eller betale for feltdata.

Feltdata er det, grænserne er skrevet til. [Chrome User Experience Report](https://developer.chrome.com/docs/crux)
indsamler anonymiserede målinger fra rigtige Chrome-brugere og leverer dem til
PageSpeed Insights og Search Consoles Core Web Vitals-rapport, uden at sitet
tilføjer noget, men først når en side eller et origin har besøgende nok.
Alternativet er et script i den besøgendes browser, der sender hver måling til
en server: en beslutning om privatliv og en omkostning ved hver sidevisning.

Laboratoriedata koster ingen af delene. Lighthouse indlæser siden på en
simuleret enhed og et simuleret netværk, før en ændring går i luften, og så tit
man vil. Det, den måler, er et besøg, ingen har aflagt. Den ser LCP og CLS under
indlæsningen, men når ingen trykker på noget, er der heller ingen INP; web.dev
tilbyder Total Blocking Time som stedfortræder i laboratoriet og siger, at den
ikke erstatter INP.

Den holdbare deling er begge dele, holdt adskilt: laboratorietal som budgetter,
der fanger en forværring, og felttal, hvor de findes, som den eneste dom over,
hvad de besøgende får.

## Sådan ser det ud i praksis

Et planlægningsnotat viser, at en Core Web Vitals-opgave blev overvejet og
fravalgt: Chrome UX Report kræver en API-nøgle og trafik nok til at rapportere,
og siderne holdes allerede til størrelsesbudgetter i gaten. Selv indsamler sitet
heller intet: kolofonen fortæller, at det
[kører ét script på omkring en kilobyte og ingen analytics](/da/credits/), og
det script, listefilteret, er det eneste, der kunne forsinke et klik eller
tastetryk. Samme side henviser til PageSpeed Insights, der viser målinger fra
rigtige besøg, når en side har nok af dem.

Sitet måler i stedet i laboratoriet. Dets Lighthouse-konfiguration indlæser en
fast liste sider tre gange hver under simuleret mobildrosling og melder fejl,
når en af de engelske eller danske sider krydser en af disse grænser: LCP over
4.200 millisekunder, First Contentful Paint over 1.600, CLS over 0,02 og Total
Blocking Time over 100, med lidt bredere grænser for de to paint-målinger på de
ukrainske sider. Det er budgetter, ikke feltgrænserne, og de blev skrevet, efter
at spredningen fra kørsel til kørsel var målt til 299 millisekunder i værste
fald og 80 i bedste, fordi en grænse inden for den spredning består eller dumper
tilfældigt. Projektets noter tilskriver det meste af LCP'en
renderingsforsinkelse bag ét stylesheet, der blokerer renderingen. Vægt, der
ankommer før noget indhold, var allerede skåret ned:
[stylesheet-bundtet vejede 87 KB med en base64-skrifttype indeni og 31 uden](/da/portfolio/cut-the-stylesheet-bundle-from-87kb-to-31kb-139/).
Kørslerne tager minutter, så de sker efter behov, uden for gaten.

CLS-budgettet, fem gange strengere end grænsen på 0,1, fangede en sag, der er
værd at gemme. En kategoriside dumpede med 0,107. Ejeren åbnede den, så intet
galt og sagde det. Lighthouse havde udpeget parallakse-tandhjulene som synderen,
og den første skriftlige diagnose troede på det. En kontrolleret test med rigtig
rulning på musehjulet gav 0,2477, uanset om tandhjulene bevægede sig, mens
overskriften og det sidste afsnit flyttede sig nul pixel hele vejen. Årsagen var
footeren: den er fastgjort til viewporten og skifter højde, når den folder sig
ud, og målingen scorer den boks mod viewporten, selv om et fastgjort element
ikke kan skubbe til noget. Budgettet blev, hvor det var; skal tallet nogensinde
tystes, er planen en undtagelse for netop den ene adresse.

## Hvor det går galt

**En laboratorierapport udelader INP, og siden antages at reagere hurtigt.**
Lighthouse viser LCP, CLS og en lav Total Blocking Time, og langsomme klik i
produktion kommer som en overraskelse. En simuleret indlæsning har ingen, der
interagerer, og Total Blocking Time tæller kun blokering af hovedtråden under
den indlæsning. Læs den som en advarselslampe, tag tid på rigtige interaktioner
i browserens ydelsesværktøjer, og bedøm INP ud fra feltdata, hvor de findes.

**Det element, et værktøj udpeger, viser sig at være uskyldigt.** Rapporten
navngiver en knude for et layoutskift, en ændring af knuden rykker scoren med
nul, og teksten på skærmen står stille. Attributionen navngiver knuder, ikke
årsager; skiftet kan stamme fra et fastgjort overlay, der skifter højde, hvilket
tæller som bevægelse og ikke bliver tilgivet af rulning. Slå de mistænkte fra én
ad gangen, mål, om indholdet flytter sig, og animér størrelse med `transform`,
som web.dev anbefaler, fordi det ikke giver layoutskift.

**Indholdet hopper nedad, efterhånden som billeder og sene elementer indlæses.**
Læserne mister deres plads, og CLS i felten stiger over 0,1. web.dev nævner de
typiske årsager: billeder og video uden kendt størrelse, webskrifttyper, der
tegnes større eller mindre end reserveskrifttypen, og widgets, der ændrer deres
egen størrelse. Giv hvert billede attributterne `width` og `height`, så
browseren reserverer pladsen, sådan som sitets billedpartials gør, og reservér
plads til alt, der indsættes senere.

**Et pænt gennemsnit skjuler en vurdering, der dumper.** Et dashboard viser en
gennemsnitlig LCP et godt stykke under 2,5 sekunder, men siden vurderes til at
trænge til forbedring. Vurderingen bruger 75-percentilen pr. enhedstype, og en
langsom fjerdedel af mobilbesøgene forsvinder i et gennemsnit, der også rummer
hurtige desktops. Rapportér og sæt mål på 75-percentilen, delt op efter enhed.

## Læs mere

- [Web Vitals](https://web.dev/articles/vitals) — de tre målinger, deres grænser
  og de værktøjer, der rapporterer dem.
- [Defining the Core Web Vitals metrics thresholds](https://web.dev/articles/defining-core-web-vitals-thresholds)
  — hvorfor 75-percentilen, og hvordan hver grænse blev afprøvet.
- [Interaction to Next Paint](https://web.dev/articles/inp) — hvad der tæller
  som en interaktion, og hvordan INP adskiller sig fra First Input Delay.
- [Largest Contentful Paint API](https://wicg.github.io/largest-contentful-paint/)
  — hvilke elementer der er kandidater, og hvornår deres tid tages.
- [Layout Instability API](https://wicg.github.io/layout-instability/) — scoren
  for layoutskift, nylig input og kilderne til hvert skift.
- [Event Timing API](https://w3c.github.io/event-timing/) — hvordan ventetiden
  ved interaktioner gøres tilgængelig for scripts.

<https://engineer.company/da/glossary/core-web-vitals/>
