Charts · 35
The 16.7ms frame budget
A 60 Hz screen asks for a new picture every 16.7 ms; a 120 Hz screen every 8.3. Inside that window the browser has to take the input, run your JavaScript, restyle, lay out, paint and composite, and when the sum runs over, the screen shows the old frame again. That repeated frame is jank. First feel it on your own screen, then see one frame laid out stage by stage against both deadlines.
What it feels like
Measuring your display…
Each bar is the time between two frames, measured with the timestamp requestAnimationFrame passes in; the newest is on the right. The ball is moved from JavaScript, one frame at a time, so it stutters exactly when a bar jumps. Add work and watch the bars leave the line: past your frame interval every frame takes two, then three. If you have a 120 Hz screen, frames start arriving late at about 8 ms of work, half what a 60 Hz screen tolerates.
One frame, to scale
11.0 ms of work in this frame. Typing into a field that a framework re-renders: the handler, the reconcile, a restyle and relayout of what changed. These are the keypress chart's typical figures. It fits a 60 Hz frame and misses a 120 Hz one.
60 Hz · 16.7 ms per frame · fits, 5.7 ms to spare
120 Hz · 8.3 ms per frame · misses by 2.7 ms, ready after 2 refreshes: 1 frame dropped
Pick a stage
The bar is one frame’s work, the shaded box is the time a frame has, and the ticks are the screen refreshing. The dashed line in the 60 Hz row is web.dev’s 10 ms: of a 16.7 ms frame, the browser needs about 6 for itself, so they tell you to keep yours to 10. Stage costs are illustrative; the meter above measures yours.
Where jank comes from
Long tasks
One task over 50 ms holds every frame and every input queued behind it. The fix is to break the work up and yield between pieces.
web.dev, Optimize long tasks · the chart: The event loop, for interfaces
Slow handlers on input
The time from a tap to the next frame is input delay, then your handlers, then the frame. INP calls 200 ms or less good; a single frame's worth is the goal for typing.
web.dev, Interaction to Next Paint · the chart: How a keypress becomes a pixel
Animating layout properties
top, left, width, height and margin re-run layout and paint on every frame. transform and opacity skip both and can run on the compositor.
web.dev, Rendering performance · the chart: What a CSS property costs
Forced layout in a loop
Reading offsetHeight or getBoundingClientRect after a style write makes the browser lay out now, inside your script. In a loop, that is a layout per iteration. Read everything first, then write.
web.dev, Avoid large, complex layouts and layout thrashing
Expensive paint
Paint is often the longest stage. Anything with a blur, like a large box-shadow or a backdrop filter, costs more than a flat fill, and a big repainted area costs more than a small one.
web.dev, Simplify paint complexity and reduce paint areas · the chart: What a CSS property costs
Too much JavaScript to start
Parsing, compiling and running a large bundle is main-thread time before the page can answer anything.
Chrome for Developers, Inside look at modern web browser, part 3 · the chart: What a byte of JavaScript costs