Artikel

Animation performance — Frame rate og jank-fri bevægelse

Animation performance handler om at holde 60 fps. CSS-animationer på compositor-properties (transform, opacity) er hurtige. JavaScript-animationer og layout-triggerende properties er dyre.

Animation performance er den del af web performance der handler om flydende bevægelse — at holde 60 fps og undgå jank. Browseren har 16,7 millisekunder per frame til at eksekvere JavaScript, beregne styles, layoute elementer og komposittere dem. Forstår man hvilke CSS-properties der trigger hvilke trin i rendering-pipeline, kan man skelne de dyre animationer fra de billige og bygge brugergrænseflader der reagerer uden hakken.

Animation på web er tilgængeligt via CSS transition og animation, JavaScript requestAnimationFrame, Canvas og WebGL, SVG-animationer, video og GIF. Performance-implikationen varierer markant — en dårligt implementeret animation kan resultere i jank og direkte forringe INP-scoren.

Frame rate og 60 fps-målet

Browseren opdaterer skærmen typisk 60 gange per sekund — 60 fps. Det giver 16,7 millisekunder per frame. Indenfor den tid skal browseren: eksekvere JavaScript, beregne styles, layoute elementer, male pixels og komposittere lag.

Hvis ét step tager for lang tid, droppes en frame. Brugeren ser et hak — jank.

Rendering-pipeline og hvad der er dyrt

Browseren gennemgår disse trin for at vise et frame:

JavaScript → Style → Layout → Paint → Composite

Forskellige CSS-ændringer triggler forskellige trin:

  • Layout-triggerende properties (width, height, margin, top, left): Tvinger browseren til at genberegne hele layout-træet. Dyrt.
  • Paint-triggerende properties (color, background, box-shadow): Kræver genmaaling af pixels. Moderat dyrt.
  • Compositor-only properties (transform, opacity): Håndteres udelukkende på compositor thread, bypasser JavaScript og layout. Næsten gratis.

CSS-animationer — den hurtige vej

Animér udelukkende transform og opacity for jank-fri resultater:

/* Hurtigt — kun compositor */
.element {
  transition: transform 0.3s ease, opacity 0.3s ease;
}

.element:hover {
  transform: translateY(-4px);
  opacity: 0.85;
}
/* Langsomt — trigger layout */
.element {
  transition: top 0.3s ease, width 0.3s ease;
}

will-change: transform kan bruges til at promovere et element til sit eget compositor-lag — men brug det sparsomt, da hvert lag kræver hukommelse.

JavaScript-animationer med requestAnimationFrame

requestAnimationFrame er den korrekte måde at lave JavaScript-animationer:

function animate(timestamp) {
  element.style.transform = `translateX(${position}px)`;
  position += speed;
  requestAnimationFrame(animate);
}

requestAnimationFrame(animate);

Undgå setInterval eller setTimeout til animationer — de er ikke synkroniseret med browser-refresh og skaber ujævne frames.

Layout thrashing er et klassisk JavaScript-animationsproblem: du læser en layout-property (f.eks. element.offsetTop), skriver til DOM, læser igen — og tvinger browseren til at genberegne layout gentagne gange. Batch reads og writes separat.

Måling og debugging

Chrome DevTools Performance-panel visualiserer frames, long tasks og hvad der foregår per frame. Frames der tager over 16,7ms markeres som lange. Rendering panelet kan aktivere “Frame Rendering Stats” der viser fps live.

Lighthouse måler ikke animation jank direkte, men INP-scoren afspejler responsivitet — og animationer der blokerer main thread forringer INP. → Denne artikel er en del af Web Performance — Core Web Vitals og teknisk hastighed.

Andre artikler i samme emne

Ofte stillede spørgsmål

Hvad er jank i web-animationer?
Jank er visuelle hakken og uregelmæssigheder i animationer — frames der dropper under 60 fps. Det opstår når browseren ikke kan nå at beregne, komposittere og male en ny frame inden for 16,7 millisekunder. De hyppigste årsager er tunge JavaScript-beregninger på main thread og CSS-animationer der trigger layout reflow.
Hvad er forskellen på CSS og JavaScript-animationer performance-mæssigt?
CSS-animationer på `transform` og `opacity` kører på compositor thread og bypasser main thread — de er i praksis gratis performance-mæssigt. JavaScript-animationer via requestAnimationFrame kan matche CSS-performance men kræver disciplin: hold beregninger lette, undgå layout-reads og -writes i samme frame, og brug compositor-only properties.
Hvad er will-change og hvornår skal det bruges?
will-change er en CSS-property der signalerer til browseren at et element vil blive animeret, så browseren kan promovere det til sit eget compositor-lag på forhånd. Det reducerer jank ved komplekse animationer, men har en pris: hvert compositor-lag bruger GPU-hukommelse. Brug will-change: transform kun på elementer der faktisk animeres, og overvej at fjerne det igen efter animationen med JavaScript.
Hvad er layout thrashing og hvordan undgår man det?
Layout thrashing opstår når JavaScript skifter mellem at læse og skrive layout-properties i hurtig rækkefølge — for eksempel læse offsetTop, skrive width, læse offsetTop igen. Browseren er tvunget til at genberegne layout ved hvert læse-kald for at returnere opdaterede værdier. Løsningen er at batch alle reads samlet og derefter alle writes samlet, gerne styret via requestAnimationFrame.
Påvirker animationer INP-scoren?
Ja, indirekte. Animationer der kører tunge beregninger på main thread kan blokere browserens evne til at reagere på brugerinteraktioner. INP måler forsinkelsen fra en bruger interagerer til siden visuelt reagerer. En tung JavaScript-animation der optager main thread under et klik forringer INP direkte. CSS-animationer på compositor-properties (transform, opacity) påvirker ikke main thread og har dermed ingen INP-effekt.

Placering i ordbogen

Animation performance — Frame rate og jank-fri bevægelse