will-change
Hints the browser about upcoming property changes for optimization. Overuse degrades performance; reset with wca.
Class List
| Class | CSS | Description |
|---|---|---|
wca | will-change: auto | Default. Browser decides optimization automatically |
wct | will-change: transform | Hint transform will change (GPU accel) |
wco | will-change: opacity | Hint opacity will change |
wcsp | will-change: scroll-position | Hint scroll-position will change |
wcc | will-change: contents | Hint contents will change |
Visual Demo — Why Nothing Changes
Both boxes scale identically on hover. Only the right one carries the hint class, and there is no visible difference at all, because this property does not change appearance: it tells the browser to get ready.
tall300msease
tall300msease wca
The difference lives inside the browser, not on screen. A hinted element may be promoted to its own layer ahead of time so the first frame is smoother, and it holds on to that memory for as long as the hint stays.
Usage Examples
will-change creates a separate layer for GPU acceleration. Always reset after animations.
<!-- Atomic CSS supports will-change: auto (wca) —
the browser default / reset value. -->
<!-- Reset will-change after an animation finishes -->
<div class="wca">
Element with will-change reset to auto
</div>
<!-- Tip: for a specific hint like will-change: transform,
the browser also auto-optimizes elements that already have
a transition/animation, so tall200msease + hover-ts1-1
already gets GPU acceleration without a will-change hint. -->
<div class="tall200msease hover-ts1-1">
Card that scales up on hover (auto-optimized)
</div>Class Details
wcawill-change: auto
The default value and, in practice, the off switch. It lets the browser decide, and it is what you set once an animation is done to drop the hint. It is also the value shipped as a real class in this set.
<!-- Drop the hint again once the animation is done -->
<div class="wca tall300msease">
Back to letting the browser decide.
</div>wctwill-change: transform
Announces that a transform is about to change. Add it just before a heavy movement such as a drawer opening or a carousel advancing, and remove it the moment the movement ends.
<!-- Panel that is about to slide in from the right -->
<aside class="wct tall300msease pf t0 r0 h100vh w30rem bg18181B">
Remove the hint as soon as the slide finishes.
</aside>wcowill-change: opacity
Announces that opacity is about to change. It is only worth it for large areas, such as a full-screen overlay fading in.
<!-- Full-screen overlay fading in: a large area of opacity -->
<div class="wco tall300msease o0 pf t0 l0 w100p h100vh bg0-0-0-50"></div>wcspwill-change: scroll-position
Announces that the scroll position is about to change. Add it right before scrolling a long list programmatically and drop it once scrolling stops.
<!-- Long list about to be scrolled programmatically -->
<div class="wcsp oya h40rem">
<p class="fs14px c71717A">Thousands of rows.</p>
</div>wccwill-change: contents
Announces that the element content itself changes constantly. It stops the browser from caching a painted picture of the element, so reserve it for canvas-like regions that repaint every frame.
<!-- Region whose content is repainted every frame -->
<div class="wcc w100p h30rem bg18181B br8px">
Live chart output.
</div>Practical Example — Hint Only Just Before the Drawer Opens
Instead of baking the hint into the markup, it is added in code when the pointer reaches the open button and removed when the animation finishes. That is the only safe way to use this property.
<!-- Markup ships WITHOUT the hint -->
<button id="open-drawer" class="bg6366F1 cFFFFFF br6px py12px px16px fs14px">
Open
</button>
<aside id="drawer" class="tall300msease pf t0 r0 h100vh w30rem bg18181B">
<p class="p2rem fs14px cA1A1AA">Drawer contents</p>
</aside>
<!-- JS adds the hint on pointer approach, removes it after the animation:
open.addEventListener('pointerenter', () => drawer.classList.add('wct'));
drawer.addEventListener('transitionend', () => drawer.classList.remove('wct'));
Leaving 'wct' on permanently would pin a compositor layer for the whole
session, which costs memory and can slow the page down. -->Tips / Caveats
Never leave it on permanently
A hinted element is promoted to its own layer and holds that memory for as long as the hint exists. Put it on every row of a list and you create hundreds of layers, which makes scrolling worse, not better. Add it only for the moment you need it and take it off right away.
Adding it at hover time is already too late
The whole point is to give the browser time to prepare. Adding it at the exact moment the animation starts leaves no time at all, so you get none of the benefit and pay the layer creation cost mid-animation.
Most transitions do not need it
Transform and opacity animations are already optimized by the browser. Reach for it as a last resort, after you have measured real dropped frames.
It creates a stacking context and reorders overlaps
A hinted element establishes a new stacking context. If a dropdown suddenly hides behind a sibling, or a fixed element gets clipped oddly, this property is a likely cause.
Hint the property you actually change
Hinting transform and then animating width and height wastes the preparation and still triggers layout. Keep the hint and the animated property in sync.
Do not overuse — causes performance degradation
Applying to all elements creates unnecessary layers, increasing memory and worsening performance.
Add before animation, remove after
Add will-change via JavaScript before animation, reset with wca after.
Use as last resort
Most CSS transitions/animations auto-optimize. Apply will-change only when performance issues confirmed.