22. Compositing and the GPU: layers, rasterization, the 16.6ms frame budget, jank
At 60Hz, the browser has 16.6ms to go from "something changed" to "a new frame is on screen" — miss that budget and a frame is dropped, which the human eye perceives as jank (stutter). The budget is shared:
16.6ms frame budget, roughly:
JavaScript (event handlers, your animation logic) |
Style recalculation (CSSOM re-match) | all on the MAIN thread
Layout (if triggered) |
Paint (if triggered) |
Composite — can run on a SEPARATE compositor
thread, independent of main-thread JS
Elements get promoted to their own compositor layer (visible in DevTools
via the "Layers" panel) when they have a transform/opacity animation,
will-change, <video>, or a few other triggers — once promoted, the GPU
can move/fade that layer independently, without asking the main thread to
redo any work, which is exactly why compositor-only animations stay smooth
even while the main thread is busy running your JS.
/* Hint the browser to promote this element to its own layer BEFORE the
animation starts, avoiding an expensive layer-promotion mid-animation. */
.will-animate {
will-change: transform;
}
Overusing will-change is a real anti-pattern: every promoted layer costs
GPU memory, and a page with hundreds of unnecessary layers can be slower
than one with none — apply it narrowly, right before an animation starts,
and remove it after.