transform and opacity Performance
Why transform and opacity animate smoothly — compositor layers, paint vs layout, and when filters and will-change reverse the win.
- css
- performance
- transform
- opacity
Browsers optimize animations of transform and opacity because they can often run on the compositor without re-laying out the document. Animating width, top, or margin forces layout (and often paint) on every frame — jank city on mobile.
Docs: web.dev animations, MDN transform, rendering performance.
The pipeline (short)
- JS / style →
- Layout (geometry) →
- Paint (pixels into layers) →
- Composite (layers GPU-ish)
Transform/opacity changes can skip layout and sometimes skip repainting descendants’ full trees by re-compositing existing layers.
/* Prefer */
.drawer {
transform: translateX(100%);
transition: transform 200ms ease;
}
.drawer.is-open {
transform: translateX(0);
}
/* Avoid for 60fps UI */
.drawer-bad {
right: -100%;
transition: right 200ms ease;
}
Opacity for fades
.toast {
opacity: 0;
transition: opacity 160ms ease;
}
.toast.is-open {
opacity: 1;
}
Opacity still creates a stacking context when < 1. Don’t invent extra layers on hundreds of nodes without need.
translateZ / translate3d myths
.card {
transform: translateZ(0); /* old “force layer” hack */
}
Promoting everything to its own layer increases memory and can hurt. Prefer letting the browser promote when animating, or use will-change briefly (see its article).
What still costs
| Change | Typical cost |
|---|---|
transform, opacity |
Composite (best case) |
filter, large box-shadow changes |
Paint + composite |
width, height, top, left, margin |
Layout + paint |
background-color |
Paint |
| Scroll-linked layout reads | Layout thrash if mixed with writes |
/* Mixed: opacity ok, blur expensive if animated continuously */
.modal-backdrop {
opacity: 0.5;
backdrop-filter: blur(8px); /* cost on scroll underneath */
}
FLIP and layout animations
When you must animate layout (reorder lists), measure first (FLIP: First, Last, Invert, Play) and animate only transform between positions. Libraries implement this; the principle is still transform-based motion.
Reduced motion
Performance wins don’t override vestibular safety:
@media (prefers-reduced-motion: reduce) {
.drawer {
transition: none;
}
}
Interview out-loud
“I animate transform and opacity because they can be composited without layout. I avoid animating width/top/margin for continuous UI motion. Layer promotion isn’t free, so I don’t blanket translateZ(0). Filters and backdrop blurs can still be paint-heavy. I verify with Performance panel paint flashing when something janks.”
Footguns
- Animating
height: autowithout a modern strategy. - Infinite blur animations.
- Reading layout in scroll handlers every frame.
- Too many simultaneous layers on low-end Android.
- Using transform for positioning permanently without updating focus/scroll logic (hit testing is fine; document flow isn’t updated).
Measuring jank
- Chrome Performance panel → enable screenshots.
- Look for long frames during the animation.
- Paint flashing / layer borders in Rendering tools.
- Compare
transformversion vstopversion of the same drawer.
If the main thread is busy with React render work, compositor-friendly CSS cannot save you — split the problem (defer render, reduce work) separately from paint strategy.
.skeleton {
opacity: 0.6;
animation: pulse 1.2s ease-in-out infinite;
}
@keyframes pulse {
50% { opacity: 0.35; }
}
@media (prefers-reduced-motion: reduce) {
.skeleton { animation: none; opacity: 0.5; }
}
Related
Further reading
Related guides
- will-change Pitfallswill-change hints the browser to prepare layers — use sparingly, set only before animation, and remove after to avoid memory bloat.
- Accent Color and Form ControlsUse accent-color to theme native checkboxes, radios, ranges, and progress — what it paints, what it skips, and when to custom-style instead.
- Auto-fit vs Auto-fillauto-fit collapses empty tracks; auto-fill keeps them. Use both with minmax for responsive card grids without media-query soup.
- BEM Naming MethodologyBlock, Element, Modifier naming for CSS — how it limits specificity wars, what to name, and when utility or CSS modules beat strict BEM.
- blend-mode Basicsmix-blend-mode vs background-blend-mode — how pixels combine, isolation, and the stacking/readability traps in product UI.