CSSwill-change

will-change

will-change is a hint to the browser: "this property is about to change, plan ahead." It exists purely for performance — it changes nothing about how an element looks, only how the browser prepares to render it. Used well it removes a hitch at the start of an animation; used carelessly it burns memory and can make things slower.

What the hint actually does — layer promotion

Browsers render in layers composited together on the GPU. An element that changes via transform or opacity can often be updated by moving/fading its own layer, skipping layout and paint entirely (see Layer Promotion & Compositor). Creating that separate layer costs time, though — normally the browser only promotes an element to its own layer once an animation actually starts, causing a small stutter right at that moment. will-change tells the browser to do that promotion work early, before the animation begins, so the expensive part is already done by the time it matters.

CSS
.card {
  will-change: transform;
}

.card:hover {
  transform: translateY(-4px);
}
When it helps
  • A large or complex element (heavy box-shadow, filters, lots of child content) that stutters on the very first frame of a hover/transition, but is smooth afterward — the classic sign the promotion cost is happening at the wrong time.

  • An element you know with certainty is about to animate very soon — for example, right before triggering a modal open transition.

  • Scroll-linked or drag-driven transforms, where the element updates every frame and benefits from staying on its own compositor layer for the whole interaction.

When it hurts — the memory cost

Every layer the browser creates consumes GPU memory, and a page with dozens of promoted layers can run out of that budget, forcing the browser to demote layers, merge them, or slow down elsewhere to compensate — the opposite of the intended effect. will-change applied broadly (every card in a grid, every list item) or left on permanently is the most common way this backfires.

Usage pattern

Effect

Applied to one element, right before it animates, removed after

Fast — this is the intended pattern

Applied to a whole list/grid of items "just in case"

Wastes memory on layers for elements that may never animate

Left on permanently in a stylesheet

The element stays promoted forever, paying the memory cost with no matching benefit once the animation is over

Applied to will-change: all

Promotes on every property change — almost always the wrong choice; name the specific property instead

Warning
Never write will-change: all and never apply will-change to more elements than are about to actually animate — both defeat the purpose by asking the browser to pre-allocate resources it may never need.
The correct usage pattern — add, then remove

The most reliable pattern applies will-change via JavaScript right before the animation starts and removes it right after it finishes, rather than leaving it in a static stylesheet rule.

HTML
const card = document.querySelector('.card');

card.addEventListener('mouseenter', () => {
  card.style.willChange = 'transform';
});

card.addEventListener('transitionend', () => {
  card.style.willChange = 'auto'; // release the layer once done
});
Note
For a hover-driven transition specifically, this JS dance is often unnecessary overhead — a static will-change: transform on a small, bounded number of interactive elements (a handful of buttons or cards, not hundreds) is a reasonable, simpler compromise. Reserve the add/remove JS pattern for animations on many elements at once, or ones triggered programmatically rather than by hover.
Naming the specific property

CSS
/* Good — tells the browser exactly what's coming */
.panel { will-change: transform, opacity; }

/* Avoid — over-broad, promotes for changes that don't need it */
.panel { will-change: all; }
Alternatives — the old translateZ(0) hack

Before will-change existed, developers forced layer promotion with a no-op 3D transform — transform: translateZ(0) or translate3d(0,0,0) — which had the side effect of triggering GPU compositing. It works in every browser that supports 3D transforms, but it is a hack repurposing a visual property for a performance side effect, with no way to ever "undo" it short of removing the transform, and it can introduce subtle rendering differences (blurrier text, changed subpixel rounding) that will-change avoids.

will-change

translateZ(0) hack

Purpose-built for this

Yes

No — repurposes a visual transform

Can be toggled off cleanly

Yes (will-change: auto)

Awkward — removing it means removing a real transform value

Side effects on rendering

None

Can subtly affect text rendering/subpixel positioning

Still relevant today

The correct modern choice

Legacy fallback for very old browser support only

Measuring with DevTools layers
  • Chrome DevTools → More tools → Layers panel shows every compositor layer currently created, including why each one exists (a tooltip lists the promotion reason, e.g. "will-change: transform").

  • The Rendering tab has a "Layer borders" option that outlines every layer directly on the page — a quick visual check for whether you have far more layers than expected.

  • The Performance panel's frame timeline shows whether a given frame did Layout + Paint + Composite, or skipped straight to Composite — the direct evidence that a will-change (or transform-only animation) is paying off.

Tip
If the Layers panel shows a large number of promoted layers you did not expect, look for stray permanent will-change declarations left in a stylesheet from an earlier optimization pass — they are easy to add and easy to forget to remove.