ESC

Type to search the knowledge base.

Compositor Layers

When browsers promote layers, why transform/opacity animate cheaply, and layer explosion costs.

advanced3 min read
  • browser
  • compositor
  • layers
  • rendering
  • performance

After layout and paint, the browser often composites pre-painted layers on the GPU. Animating properties that only need recomposite (transform, opacity in favorable cases) avoids layout and sometimes paint. Promoting everything to its own layer is not free — memory and upload costs explode.

Docs: web.dev Animations guide, Layers panel / rendering, CSS triggers.

Pipeline reminder

DOM/CSSOM → style → layout → paint → composite → pixels

Composite is last. If a property only invalidates composite, you skip expensive earlier stages for that frame.

What tends to create layers

Browsers use heuristics. Common promoters:

  • transform / opacity animations or will-change
  • position: fixed / sticky in some cases
  • 3D transforms (translateZ(0) hacks — treat as last resort)
  • <video>, canvas, some filters
  • Overflow scrolling containers
.modal {
  transform: translateY(0);
  transition: transform 200ms ease, opacity 200ms ease;
  will-change: transform; /* only while animating if you can */
}

Prefer animating transform/opacity. Animating top, left, width, height usually forces layout.

DevTools: prove it

  1. Performance recording → look for Paint vs Composite Layers.
  2. Layers panel / Rendering → Layer borders to see promotions.
  3. If every card is a layer, you may have over-promoted.

Layer explosion

Each layer costs memory (backing store). Mobile GPUs run out of patience:

Symptom Likely cause
Scroll jank with many will-change: transform Too many layers
Memory growth on list pages Promoting every row
First animation smooth, later lag Layer count scales with DOM
/* Bad at list scale */
.list-item {
  will-change: transform;
  transform: translateZ(0);
}

Promote the moving element for the duration of the animation, then clear will-change.

Paint containment vs layers

contain: paint / content-visibility reduce invalidation work; they are not the same as compositor layers but often pair with performance work. Virtualize long lists so you never paint thousands of cards — virtual lists.

Main thread vs compositor thread

Scroll and transform-only animations can run on the compositor thread when layers are ready and main thread isn’t forcing updates. Heavy JS on main still causes INP issues even if scroll is smooth. See Main thread vs compositor.

Practical rules

  1. Animate transform/opacity when possible.
  2. Don’t sprinkle translateZ(0) as cargo cult.
  3. Use will-change sparingly and temporarily.
  4. Measure layer count on real pages, not demos.
  5. Reduce paint area (overflow hidden, containment) when paint shows up in profiles.

Interview out-loud

“Compositor layers let the GPU glue pre-painted textures. Transform and opacity can skip layout/paint; overusing will-change creates memory-heavy layer explosion. I verify with Performance and Layers, not folklore.”

Mobile memory note

Each additional layer can allocate a full-size texture. A product listing grid with will-change: transform on every card may look smooth in a desktop Performance recording and OOM on a low-end Android device. Prefer promoting the carousel track or the single dragging element, not every cell.

Further depth

Teams often under-invest in this topic until an incident or CWV regression. Schedule a one-hour drill: reproduce the failure mode in DevTools, list the top three mitigations for your stack, and file tickets with owners. Revisit after the next major feature that touches networking, rendering, auth, or third parties — those are the moments regressions land. Keep primary documentation links in the runbook so on-call is not searching chat history at 2am.

Concrete artifacts to leave behind: a short architecture note, a CI assertion or header snapshot, and a dashboard panel (lab or field) that would have caught the last bug. Teaching the rest of the team the mental model matters as much as the one-line fix.

Further reading

Related guides