A CSS animation on an element hidden with visibility: hidden
keeps triggering per-frame paint invalidation work in Blink even though the
element paints nothing. The animation must keep running per spec; the paint
invalidation is pure overhead.
Three animations run below: a transform spinner, a
background-color pulse and a color text pulse.
Toggle them between visibility: hidden, visible
and display: none.
transform and background-color are composited
in modern Chrome: cc has no layer to tick once the element paints nothing,
so they go idle when hidden. color is not compositable -- it
animates on the main thread and is the case that keeps repainting while
hidden.
Each cell has its own state so the cases can be isolated: once any
main-thread animation forces main frames, the other animations tick along
with it and pollute the measurement. To measure one case, set the other
cells to display: none.
1. Set the demo to visibility: hidden (default).
2. Click "isolate color case" (color cell hidden, composited cells display: none), then open DevTools > Performance and record a few seconds. "Frame Rendering Stats" is the wrong tool here: no frames are presented while hidden either way, so it stays quiet even on affected builds.
3. Unpatched Chrome shows per-frame main-thread rendering work
(paint invalidation, pre-paint, paint) despite nothing being drawn. Set
the color cell to display: none too and the timeline goes
idle.
Isolating a composited cell as hidden instead shows an idle timeline
already: that half of the bug is fixed by compositor-driven
animations.
Continuous per-frame paint work for the main-thread color
animation while it is invisible (same as when it is visible).
Only style recalc remains; no paint invalidation or paint work while the element stays hidden.
Issue 41254682 (formerly crbug.com/613166)