Skip to content

Compositing & GPU

Compositing is the final stage of the rendering pipeline where the browser combines painted layers into the final image. Changes that only affect compositing are the most performant because they skip layout and paint.

The following CSS properties only trigger compositing (no layout, no paint):

/* ✅ GPU-accelerated — cheapest animations */
.element {
transform: translateX(100px);
transform: rotate(45deg);
transform: scale(1.5);
opacity: 0.5;
}
// ❌ Expensive — triggers reflow each frame
function animateLeft() {
const el = document.getElementById('box');
let left = 0;
function frame() {
left += 2;
el.style.left = left + 'px'; // Triggers layout!
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
}
// ✅ Cheap — only compositing
function animateTransform() {
const el = document.getElementById('box');
let x = 0;
function frame() {
x += 2;
el.style.transform = `translateX(${x}px)`; // Compositing only 🚀
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
}
// Hint the browser to promote to a compositor layer
// CSS
element.style.willChange = 'transform';
// Or in CSS:
// .animated {
// will-change: transform, opacity;
// }
// OR use translate3d to force GPU layer (older trick)
element.style.transform = 'translate3d(0, 0, 0)';

Properties that promote an element to its own compositor layer:

  • transform (3D or 2D)
  • opacity
  • will-change
  • filter
  • position: fixed
  • <video>, <canvas>, <iframe> elements
  • Elements with mix-blend-mode
.button {
/* Creates a compositor layer */
transform: translateZ(0);
}
.card {
/* Hints browser to promote to a layer */
will-change: transform, opacity;
}
.modal {
/* Fixed positioned elements get their own layer */
position: fixed;
will-change: transform;
}
PropertyLayoutPaintCompositeBest for
left/top❌❌✅Never animate
width/height❌❌✅Never animate
color/background✅❌✅Occasional
transform/opacity✅✅✅Animations 🚀