CSS will-change Property
Use the will-change CSS property for specifying how an element is expected to change in the future. Read about property and try examples.
The will-change property gives the browser a hint about how an element is expected to change in the near future, so the browser can set up the necessary optimizations before the change actually happens — rather than scrambling to optimize on the very frame the change begins.
This page covers what will-change does, when (and when not) to reach for it, its accepted values, a runnable example, and the pitfalls that make it easy to misuse.
Why will-change exists
Properties like transform and opacity are cheap to animate because the browser can promote the element to its own compositing layer (a separate surface the GPU can move, fade, or scale without repainting the rest of the page). Creating that layer, however, costs time and memory. If the browser only discovers it needs a layer at the moment an animation starts, the first frame can stutter.
will-change lets you tell the browser ahead of time which properties are about to change, so it can prepare the layer in advance and keep the animation smooth from the very first frame.
The values are comma-separated. The will-change property accepts these values: auto, a <custom-ident> such as a property name (transform, opacity, scroll-position, …), initial, inherit, or unset.
This property should be used with caution. Different browsers handle this property differently, and overusing it may cause the browser to ignore it. Overuse can also force unnecessary compositing layers, increasing memory usage and degrading performance.
Proper usage of the will-change property
- Don't apply it to too many elements. Each
will-changehint can force the browser to keep a compositing layer alive, which consumes memory. Hint hundreds of elements and you can slow the page down instead of speeding it up. - Add and remove it with script, around the change. Set
will-changeshortly before the change (for example onmouseenterorfocus), then remove it once the animation finishes so the browser can release the layer. - Don't use it as a premature optimization. If a page already animates smoothly, leave it alone. Reach for
will-changeonly to fix a measured performance problem — it's a last resort, not a default. - Give the browser time to prepare. The point of
will-changeis to warn the browser ahead of the change. Setting it on the same frame the animation starts defeats the purpose. - Be aware it can affect rendering. Values that create a stacking context (such as
will-change: opacityorwill-change: transform) can change how the element layers against its siblings, just as actually setting those properties would.
| Initial Value | auto |
|---|---|
| Applies to | All elements. |
| Inherited | No. |
| Animatable | No. |
| Version | CSS Transitions Module Level 1 |
| DOM Syntax | object.style.willChange = "transform"; |
Note: In JavaScript, the property name uses camelCase (willChange), while the CSS property uses hyphens (will-change).
Syntax
CSS will-change values
will-change: auto | <custom-ident> | initial | inherit | unset;Example of the will-change property:
CSS will-change code example
<!DOCTYPE html>
<html>
<head>
<title>The title of the document</title>
<style>
.circle {
width: 50px;
height: 50px;
transform: translate(50px, 0px);
border-radius: 30px;
}
.circle.blue {
background: #1c87c9;
will-change: transform;
}
.circle.green {
background: #8ebf42;
}
</style>
</head>
<body>
<h2>Will-change property example</h2>
<div class="circle green"></div>
<div class="circle blue"></div>
<div class="circle green"></div>
<div class="circle blue"></div>
<div class="circle green"></div>
<script>
const circles = document.getElementsByClassName("circle blue");
function update(t) {
for (let i = 0; i < circles.length; i++) {
const xpos = Math.sin(t / 1000 + 1000 * i) * 50 + 50;
circles[i].style.transform = "translate(" + xpos + "px, 0px)";
}
window.requestAnimationFrame(update);
}
update();
</script>
</body>
</html>Setting and clearing will-change with script
The recommended pattern is to add the hint just before an interaction and remove it afterward, so the browser only holds the layer while it's needed:
.card {
transition: transform 0.3s;
}
/* Hint the browser only while the user hovers. */
.card:hover {
will-change: transform;
transform: scale(1.05);
}For longer-lived or JavaScript-driven animations, toggle it in code:
const el = document.querySelector(".card");
// Prepare ahead of the change.
el.addEventListener("mouseenter", () => {
el.style.willChange = "transform";
});
// Release the optimization once it's no longer needed.
el.addEventListener("animationend", () => {
el.style.willChange = "auto";
});Values
| Value | Description |
|---|---|
| auto | Standard browser optimization should be applied. |
<custom-ident> | Specifies the CSS property expected to change or animate on the element in the near future. If the property is a shorthand, the changes will expand to all its longhand properties. |
| initial | Makes the property use its default value. |
| inherit | Inherits the property from its parent element. |
| unset | Resets the property to its inherited value or initial value, depending on the property. |
Related properties
will-change is a performance hint for the properties you actually animate. It pairs naturally with:
transform— the most commonwill-changetarget, since transforms are GPU-friendly.opacity— also composited and a frequent target for fades.transitionandanimation— the mechanisms that drive the changes you're hinting about.z-index— relevant because somewill-changevalues create a new stacking context.