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

  1. 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

  2. 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

  3. 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

  4. 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

  5. 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

  6. 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

Notes

The meter is measured, not modelled: a requestAnimationFrame loop moves the ball and records the gap between successive frame timestamps, and the slider adds a synchronous busy loop of that many milliseconds to every frame. Your refresh interval is the median gap while no work is added. A frame counts as late when its gap is more than one and a half refresh intervals. Browsers may throttle a background tab or a low-power device, and the loop pauses when it scrolls out of view.

The budgets are arithmetic: 1000 ms / 60 = 16.7 ms, 1000 ms / 120 = 8.3 ms. The stage costs in the frames are illustrative figures for a mid-range laptop, chosen to match the typical page work in How a keypress becomes a pixel, except where a source is named: the 28 ms of layout is web.dev’s worked example, and 50 ms is where the browser’s long-task API starts counting. Which stages a CSS change triggers is in What a CSS property costs; this chart is about how much of them fits before the deadline. The browser does some of the composite and raster work on other threads, in parallel with the next frame’s main-thread work, so the stages do not always queue end to end as drawn; the main thread’s share still has to fit.

Sources: Paul Lewis, Rendering performance, web.dev (the five-stage pixel pipeline, and 10 ms for your own work in a 16.66 ms frame); web.dev, Measure performance with the RAIL model (browsers need about 6 ms to render each frame; process input within 50 ms); Jeremy Wagner, Paul Lewis and Barry Pollard, Avoid large, complex layouts and layout thrashing, web.dev; Paul Lewis, Simplify paint complexity and reduce paint areas, web.dev; web.dev, Optimize long tasks and Interaction to Next Paint (INP of 200 ms or less is good); Mariko Kosaka, Inside look at modern web browser, part 3, and RenderingNG architecture, Chrome for Developers.