will-change Pitfalls
will-change hints the browser to prepare layers — use sparingly, set only before animation, and remove after to avoid memory bloat.
- css
- will-change
- performance
will-change tells the browser which properties are likely to change, allowing optimizations (often layer promotion) ahead of time. Used well, it prevents first-frame jank. Used as a permanent will-change: transform on every card, it burns memory and can make performance worse.
Docs: MDN will-change, web.dev stick to compositor properties.
Syntax
.drawer {
will-change: transform;
}
.fader {
will-change: opacity;
}
.box {
will-change: transform, opacity;
}
Valid values include specific properties, scroll-position, and contents (rarely needed). Don’t use will-change: all.
The right lifecycle
- Default: no
will-change. - Just before an interaction/animation, set it (class or JS).
- Animate transform/opacity.
- On
transitionend/animationend, remove it.
.card {
transition: transform 200ms ease;
}
.card.is-animating {
will-change: transform;
}
.card.is-raised {
transform: translateY(-4px);
}
el.classList.add("is-animating");
requestAnimationFrame(() => el.classList.add("is-raised"));
el.addEventListener(
"transitionend",
() => el.classList.remove("is-animating"),
{ once: true }
);
Why permanent will-change hurts
- Extra compositor layers consume GPU/CPU memory.
- More layers can increase composite time.
- Stacking contexts change — unexpected overlay bugs.
- Mobile browsers are less forgiving than your MBP.
/* Anti-pattern */
* {
will-change: transform;
}
When you might not need it
Modern browsers often promote layers when a transform/opacity transition starts. If profiling shows no first-frame hitch, skip will-change. Prefer fixing “animating left/width” over sprinkling hints.
Alternatives and relatives
| Tool | Role |
|---|---|
will-change |
Hint upcoming change |
transform: translateZ(0) |
Old force-layer hack — still costly if overused |
contain |
Layout/paint containment — different problem |
| Content visibility | Skip rendering offscreen content |
Interview out-loud
“will-change optimizes for known upcoming changes by letting the browser prepare. I apply it narrowly and temporarily around animations, never globally. If everything is will-changed, nothing is optimized — memory and composite costs climb. Profiling beats cargo-cult layer promotion.”
Footguns
- Shipping
will-changein resting component CSS forever. will-change: all.- Hinting properties you don’t actually change.
- Using it to “fix” layout thrash from bad animation properties.
- Ignoring stacking-context side effects on dropdowns.
When profiling says you need it
Symptoms: first frame of a transform transition stutters once, then is smooth. That can mean late layer promotion. Applying will-change: transform on hover intent (or 100ms before open) may help.
.menu-trigger:hover + .menu,
.menu-trigger:focus-visible + .menu {
will-change: transform, opacity;
}
.menu {
transition: transform 160ms ease, opacity 160ms ease;
}
Remove after close. On infinite lists, never leave will-change on hundreds of rows — recycle sparingly on the active item only.
Memory intuition
Each promoted layer stores bitmaps. Full-screen layers are expensive. Prefer animating a small drawer layer rather than promoting the entire page chrome. If DevTools layer count climbs steadily with scroll, something is promoting too aggressively.
Code review red flags
will-changein a base class applied to every cardwill-change: allwill-changewithout a removal path- Using it to “optimize” animations of
heightortop
Reject those patterns. Prefer correct animation properties first. Treat will-change like a temporary performance scalpel, not a permanent decoration.
Related
- transform and opacity performance
- CSS transitions
- Stacking contexts and z-index
- CSS animations keyframes
Further reading
Related guides
- transform and opacity PerformanceWhy transform and opacity animate smoothly — compositor layers, paint vs layout, and when filters and will-change reverse the win.
- 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.