Transform and opacity only

Transform and opacity skip layout and paint, so they stay smooth.

Emil Kowalskiemilkowal.ski
Great animationsDemo 2 ↓Read article ↗
Emil Kowalskiemilkowal.ski
A hardware-accelerated animation will remain smooth, no matter how busy the main thread is.
Great animationsDemo 1 ↓Read article ↗
Emil Kowalskiemilkowal.ski
Updating the style directly on the element fixed the issue
Building a drawer componentDemo 3 ↓Read article ↗

From emil-design-eng; demo 3 recreates a Vaul bug.

Block the main thread

Press Block, or tick Keep busy and type.

requestAnimationFrameMain thread
requestAnimationFrame(step)longest frame –
WAAPI transformCompositor
el.animate([{ transform }])
el.animate(
  [{ transform: "translateX(0)" }, { transform: "translateX(100%)" }],
  { duration: 1200, iterations: Infinity, direction: "alternate" }
);

What each property costs

Pick a property, then Run each pane.

Layout or paintBad
  1. Style
  2. Layout
  3. Paint
  4. Composite
–
Compositor onlyGood
  1. Style
  2. Layout
  3. Paint
  4. Composite
–

Variable vs direct transform

Drag a drawer, then raise Rows and Benchmark.

--swipe on the drawerBad
    setProperty("--swipe", y)– ms/move
    transform on drawerGood
      style.transform = translateY(y)– ms/move

      Why it matters, pros and cons

      Why it matters

      Transform and opacity only composite; everything else relayouts or repaints.

      Pros

      • Smooth while scripts and hydration run.
      • Siblings never reflow mid-animation.
      • Cheap on low-end phones.

      Cons

      • Scale distorts text; real resizes need FLIP.
      • Gestures still need per-frame JS; set transform directly.
      • Too many promoted layers cost GPU memory.