# will-change used sparingly and correctly

- **Pattern:** `ab-002005` (`performance-core.rendering-paint.will-change`)
- **Severity:** low
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-002005
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-002005)

## Why it matters

`will-change` promotes an element to its own GPU compositing layer (ISO-25010 resource-utilisation). Used correctly on a single animating modal, that is a genuine win. Applied globally in CSS to 20+ static elements — headers, footers, card wrappers that never move — it creates 20+ permanent GPU layers, consuming VRAM on every device. On mobile with limited VRAM, this causes compositor memory pressure, degrades scroll performance, and can make the browser drop frames on animations it would otherwise handle smoothly. Misuse is the opposite of its intended effect.

## Severity rationale

Low because overuse of `will-change` degrades GPU memory and scroll performance rather than breaking functionality, but the degradation is measurable and worsens on low-end devices.

## Remediation

Audit every `will-change` declaration and remove any that target non-animating elements:

```bash
grep -r "will-change" src/
```

For elements that animate occasionally (modals, tooltips, drawers), apply and remove `will-change` in JavaScript around the animation rather than in permanent CSS:

```ts
// src/components/modal.tsx
function animateOpen(el: HTMLElement) {
  el.style.willChange = 'opacity, transform'  // hint before animation
  el.animate(
    [{ opacity: 0, transform: 'scale(0.95)' }, { opacity: 1, transform: 'scale(1)' }],
    { duration: 200 }
  ).finished.then(() => {
    el.style.willChange = 'auto'  // release the layer after animation
  })
}
```

Keep active `will-change` declarations to 3–5 elements simultaneously. Static containers, page wrappers, and `<section>` elements must not have `will-change` set.

## Detection

- **ID:** `will-change`
- **Severity:** `low`
- **What to look for:** Count all relevant instances and enumerate each. Search CSS files, styled-components, and inline styles for `will-change` declarations. For each occurrence, verify that the element actually animates or transforms during normal use. Check whether `will-change` is applied to many elements at once (more than 5-10), to non-animating elements, or set permanently in CSS rather than added/removed in JavaScript before and after animations. Look for `will-change: transform` or `will-change: opacity` on static containers or large layout elements that do not move.
- **Pass criteria:** `will-change` is applied only to elements that genuinely undergo GPU-compositable transforms or opacity changes (e.g., animated modals, tooltips, floating buttons). It is added in JavaScript immediately before an animation starts and removed immediately after, rather than declared permanently in CSS. No more than 3-5 elements have `will-change` active simultaneously.
- **Fail criteria:** `will-change` is declared in CSS on many elements (10+) unconditionally, including elements that never animate. Static layout containers, wrapper divs, or entire sections use `will-change: transform`. The property is treated as a blanket performance improvement applied everywhere rather than a targeted hint.
- **Skip (N/A) when:** The project has no animations, transitions, or GPU-composited effects — making `will-change` irrelevant.
- **Detail on fail:** Specify the misuse. Example: `"will-change: transform applied to 23 elements in globals.css including static headers, footers, and card wrappers that never animate. Creates 23 separate GPU layers, increasing VRAM usage and harming scroll performance"` or `"will-change set permanently on all .btn elements; buttons are clicked but not continuously animated — property should be applied on hover/focus and removed after interaction"`.
- **Remediation:** `will-change` hints to the browser that an element is about to be transformed, allowing it to create a GPU compositing layer in advance. Overuse creates too many layers and harms performance. Apply it surgically:

  CSS (permanent, acceptable for elements that always animate):
  ```css
  /* Good: single animating element promoted to GPU layer */
  .modal-overlay {
    will-change: opacity;  /* fades in/out on open/close */
  }

  /* Bad: static element with will-change */
  .page-header {
    will-change: transform;  /* never moves — remove this */
  }
  ```

  JavaScript (preferred for elements that animate occasionally):
  ```ts
  function animateElement(el: HTMLElement) {
    el.style.willChange = 'transform'  // hint before animation
    el.animate([
      { transform: 'translateY(0)' },
      { transform: 'translateY(-20px)' }
    ], { duration: 300 }).finished.then(() => {
      el.style.willChange = 'auto'  // remove hint after animation
    })
  }
  ```

  Audit existing usage: `grep -r "will-change" src/` and review every result to confirm the element actually animates.

- **Cross-reference:** For related patterns and deeper analysis, see the corresponding checks in other AuditBuffet audits covering this domain.

---

## External references

- iso-25010 performance-efficiency.resource-utilization

Taxons: performance

HTML version: https://auditbuffet.com/patterns/ab-002005
