CSS Reference Property

will-change

The will-change property allows you to inform the browser ahead of time of what kinds of changes you are likely to make to an element in order to allow the browser to optimize how it handles the element ahead of time.

Using will-change, you allow the browser to prepare for certain changes that are likely to take place in the future, ahead of time. This allows it to make appropriate optimizations to render the page more quickly when these changes occur, therefore avoiding a non-trivial start-up cost which can have a negative impact on the responsiveness of a page. This way, when the actual change happens, the page updates in a snappy manner.

For example, when using CSS 3D Transforms to move an element around the screen, the element and its contents might be promoted to a “layer”, where they can render independently from the rest of the page and be composited in later. This isolates the rendering of the content so that the rest of the page doesn’t have to be re-rendered if the element’s transform is the only thing that changes between frames, and often provides significant speed benefits.

However, setting up the element in a fresh layer is a relatively expensive operation, which can delay the start of a transform animation by a noticeable fraction of a second.

In order to avoid this delay when using CSS Transforms and other CSS operations, we have long used translateZ (or sometimes translate3d) to promote elements to their own layers, thus achieving hardware-accelerated operations that run smoother and faster without glitches. However, this technique — also known as “The translateZ() (or translate3d()) Hack” — comes with a cost. Paul Lewis has written a very informative post about this that you should definitely check out if you use this technique. will-change is here to allow us to optimize our animations without having to resort to this hack — or any other hack, for the matter.

You can declare to the browser your intention to change an element’s scroll position, its contents, or one or more of its CSS property values by specifying the name of the properties you’re expecting to change, comma-separated. Most properties will have no effect when specified, as the user agent doesn’t perform any special optimizations for changes in most properties. It is still safe to specify them, though; it’ll simply have no effect.

If you expect or plan to change multiple values/aspects of an element, you can provide a list of comma-separated values. A list of comma-separated values can include predefined keywords and/or property names. (See the Examples section below.)

If any non-initial value of a property you’re declaring would create a stacking context on the element, specifying that property in will-change must create a stacking context on the element. For example, setting opacity to any value other than 1 creates a stacking context on the element. Thus, setting will-change: opacity also creates a stacking context, even if opacity is currently still equal to 1.

Similarly, if any non-initial value of a property would cause the element to generate a containing block for fixed-position elements, specifying that property in will-change must cause the element to generate a containing block for fixed-position elements.

The will-change property has no direct effect on the element it is specified on, beyond the creation of stacking contexts and containing blocks as mentioned earlier — it is solely a rendering hint to the user agent, allowing it set up potentially-expensive optimizations for certain types of changes before the changes actually start occurring.

That being said, it is important that you know that this property should be used with caution. Different browsers can use the information from will-change in different ways, and even a single browser might use it in different ways at different times. Overusing it may result in ignoring the declaration altogether. For example, a browser that promotes elements to their own “GPU layer” when they have will-change: transform specified might avoid doing that when there are too many elements declaring that, to avoid exhausting GPU memory.

Moreover, will-change shouldn’t be used unless an element is known or expected to change in the very near future (e.g within a fraction of a second). Once it is not needed anymore, it should be unset:

Set will-change to the properties you’ll actually change, on the elements that are actually changing. And remove it when they stop.—Tab Atkins Jr. (Spec Editor)

The optimizations that the browser makes for changes that are about to occur are usually costly and, as we mentioned earlier, can take up much of the machine’s resources. The usual browser behavior for optimizations that it makes is to remove these optimzations and revert back to normal behavior as soon as it can. However, will-change overrides this behavior maintaining the optimizations for much longer than the browser would otherwise do.

As such, you should always remember to remove will-change after the element is done changing, so the browser can recover whatever resources the optimizations are claiming.

Setting will-change via JavaScript allows for more fine-grained control and time for the browser to prepare for a change, and also allows you to unset it as soon as the animation event ends — you wouldn’t be able to do that if will-change were declared in CSS otherwise. Using JavaScript, you can declare your changes to the browser, and then remove will-change after the changes are done, by listening to when these changes have finished.

For example, you could listen for when the element (or its ancestor) is hovered, and then set will-change on mouseenter. If your element is being animated, you can listen for when the animation has ended using the DOM event animationEnd, and then remove will-change once animationEnd is fired.

// Rough generic example
// Get the element that is going to be animated on click, for example
var el = document.getElementById('element');

// Set will-change when the element is hovered
el.addEventListener('mouseenter', hintBrowser);
el.addEventListener('animationEnd', removeHint);

function hintBrowser() {
	// The optimizable properties that are going to change
	// in the animation's keyframes block
	this.style.willChange = 'transform, opacity';
}

function removeHint() {
	this.style.willChange = 'auto';
}

If you do want to set will-change in the style sheet to optimize for an element that might change on hover, then in order to tell the browser to optimize for a change that you expect to occur on hover, you may do something like this:

.el:hover {
    will-change: transform;
    transform: rotate()...;
}
                

This isn’t particularly wrong, but it isn’t particularly useful either. You need to declare your intention to the browser some time before the change actually happens, not when it happens, in order to give it some time to prepare for the changes and make the needed optimizations. So, in a scenario like this, you can do this:

.el {
    will-change: transform;
}

.el:hover {
    transform: rotate()...;
}
                

Or, you can set will-change when the element’s container is hovered, because it takes some time for the hover event to reach the element itself, and the browser could then use that time to prepare for the changes on the element itself:

.container:hover .el {
    will-change: transform;
}

.el:hover {
    transform: rotate()...;
}
                

To sum up, remember to use will-change with caution, don’t overuse it, and only set it only when you know the element is about to change, and remember to unset it after the changes are done.

Trivia & Notes

The will-change property was first named will-animate, before its name got changed to will-change.

Paul Lewis created a tool that would allow developers to more readily understand the ramifications of changing their styles. According to the performance ramifications of changing certain properties, you may or may not want or need to set will-change to hint the browser about the change in those properties’ values. Lewis’ tool is called

Official Syntax

Values

auto
This is the default value. It expresses no particular intent. The browser is not notified of any changes and thus does not make any optimizations to cater for any future changes.
scroll-position
Indicates that the author expects to animate or change the scroll position of the element in the near future. The browser will make the appropriate optimizations for this change ahead of time.

For example, browsers often only render the content in the “scroll window” on a scrollable element, and some of the content past that window, balancing memory and time savings from the skipped rendering against making scrolling look nice. A browser might take this value as a signal to expand the range of content around the scroll window that is rendered, so that longer/faster scrolls can be done smoothly.

contents
Indicates that the author expects to animate or change something about the element’s contents in the near future. The browser will make the appropriate optimizations for this change ahead of time.

For example, browsers often “cache” rendering of elements over time, because most things don’t change very often, or only change their position. However, if an element does change its contents regularly, producing and maintaining this cache is a waste of time. A browser might take this value as a signal to cache less aggressively on the element, or avoid caching at all and just continually re-render the element from scratch.

<custom-ident> (<user-ident>)
A <custom-ident> value (see the <custom-ident> entry for details). Indicates that the author expects to animate or change the property with the given name on the element in the near future.

For example, browsers often handle elements with transform set to a non-initial value very differently from normal elements, perhaps rendering them to their own “GPU layer” or using other mechanisms to make it easier to quickly make the sort of transformations that transform can produce. A browser might take a value of transform as a signal that it should go ahead and promote the element to its own layer immediately, before the element starts to be transformed, to avoid any delay involved in re-rendering the old and new layers.

The <custom-ident> value cannot be one of the following keywords: will-change, none, all, auto, scroll-position, and contents, in addition to the keywords normally excluded from <custom-ident>.

Note that most properties will have no effect when specified, as the user agent doesn’t perform any special optimizations for changes in most properties. It is still safe to specify them, though; it’ll simply have no effect.

Examples

The following tells the browser to expect the element’s transform property to change in order to make the appropriate optimizations ahead of time.

.el {
    will-change: transform;
}
                

The above will-change declaration should be added via JavaScript, and then removed or unset (will-change: auto) once the changes are over.

The following are all possible and valid will-change values:

will-change: contents;
will-change: scroll-position;
will-change: opacity;

/* multiple comma-separated values */
will-change: contents, transform;
will-change: scroll-position, opacity;
                

Browser Support

CSS will-change property

Method of optimizing animations by informing the browser which elements will change and what properties will change.

W3C Working Draft

Supported from the following versions:

Desktop

  • 36
  • 36
  • No
  • 24
  • 9.1

Mobile / Tablet

  • 9.3
  • 56
  • No
  • 61
  • 55

* denotes prefix required.

  • Supported:
  • Yes
  • No
  • Partially
  • Polyfill

Stats from caniuse.com

Written by

Last updated December 11, 2016 at 9:21 pm by Mary Lou

Do you have a suggestion, question or want to contribute? Submit an issue.