will-change in CSS

I've been using the will-change CSS property for a long time, but I realized I never understood exactly what it does under the hood.

Hover over the buttons to see the difference that will-change makes

Here's the difference it can make. On the left, the characters and icon shift around on hover. On the right, nothing moves that shouldn't.

no will-change vs will-change example

It's a hint to the browser, something along the lines of “hey, I'm about to animate these properties, please get ready.”

Hey, I'm about to animate transform and opacity, please get ready.
Ok, cool. I'll see what I can do.

Browsers can respond by promoting the element to its own GPU layer and pre‑allocating memory or doing nothing at all if they decide it isn’t worth it.

To understand why will-change exists, we first need to understand how browsers render anything on screen. It generally follows these three steps.

Layout

The browser figures out how big every box is and where it sits. Imagine laying out pieces on a board game. This step is mostly CPU work.

Paint

Now the boxes get filled with pixels, colors, borders, shadows and images. Think of someone coloring in the board game pieces. This also uses the CPU and some extra memory to store the painted bits.

Compose

Finally, the painted layers are handed to the GPU, which stacks them together and shows the combined frame on screen like sliding finished drawings under a sheet of glass and moving them around. This step is GPU-heavy.

If an animation touches only composite-friendly properties like transform and opacity, the browser can skip layout and paint and let the GPU handle everything.

Main Layer - CPU
Other Elements
Compositing Layer - GPU
Element with will-change

When you apply will-change, you're telling the browser that certain properties are about to change. If it agrees the hint is worth it, it can promote the element to its own compositing layer and set aside the memory for it ahead of time.

Without the hint, the browser promotes the element to its own layer only when the animation starts. That one-time promotion can cause a tiny stutter in the first frames.

globals.css
.animated-button {
  transform: translateX(0px);
  transition: transform 0.3s;
}

.animated-button:hover {
  transform: translateX(24px);
}

With will-change, the browser can pre-promote the element while the page is idle. When you hover over the button, the animation is smooth from the first frame.

globals.css
.animated-button {
  will-change: transform;
  transform: translateX(0px);
  transition: transform 0.3s;
}

.animated-button:hover {
  transform: translateX(24px);
}

If used well, will-change removes that first-frame stutter and takes work off the CPU. But it's not free. Every extra layer costs memory, so I only add it to elements that actually animate.

globals.css
/* Good - only on elements that will actually animate */
.animated-button {
  will-change: transform;
}

/* Bad - promoting every element on the page */
* {
  will-change: transform;
}

You should also specify what the changing properties are going to be. It's similar to transition, as most of the time you avoid using transition-property: all.

globals.css
/* Good - specifying exactly what will change */
.animated-button {
  will-change: transform, opacity;
}

/* Bad - invalid, the browser ignores it */
.animated-button {
  will-change: all;
}

In practice you can add any valid CSS property to will-change but only a couple make a difference.


Those include transform, opacity and filter effects like blur or brightness. Modern browsers also handle clip-path and mask fairly well. For these, the browser can move things around on the GPU without repainting.

transform
opacity
filter
clip-path
mask
scroll-position
contents

There is also scroll-position for when you're only animating the scroll offset.

globals.css
.parallax-wrapper {
  overflow: auto;
  will-change: scroll-position;
}

And contents, which tells the browser that the things inside the container will update a lot, but the container itself won't move.

globals.css
.virtual-list {
  contain: content;
  will-change: contents;
}

Properties like top or background are legal to write, but they don't do anything. The browser just reserves memory for nothing.

will-change isn't a magic performance switch. It's a heads-up.


It won't fix a fundamentally expensive animation. Browsers are already very good at optimizing rendering on their own.

Image
Emoji
without will-change
Image
Emoji
will-change: transform

You might not see a difference in every browser. Safari shows it the most.

When used thoughtfully and sparingly, it can make complex animations feel noticeably smoother, and prevent unexpected movement during animations.

More

If you enjoy articles like this and want to learn more, take a look at Interfaces, my design engineering magazine.

It’s where I share everything I know, from animation and typography to layout, color and everything else that is a part of building a great interface.

InterfacesThe Design Engineering Magazine
Head to Interfaces
NextLess Is More, More or Less