# Why Only Transform and Opacity Are GPU-Accelerated in CSS Animations: Complete Performance Guide

> Discover why only transform and opacity are GPU-accelerated in CSS animations. Learn how these properties bypass layout and paint stages for faster performance in this complete guide.

- Repository: [Emil Kowalski/skills](https://github.com/emilkowalski/skills)
- Tags: performance
- Published: 2026-08-02

---

**Only `transform` and `opacity` are GPU-accelerated because they skip the browser's layout and paint stages entirely, running purely during the compositing phase.**

CSS animations can achieve smooth 60fps performance only when the browser offloads work to the GPU. The `emilkowalski/skills` repository codifies this as a strict performance rule: **only animate `transform` and `opacity`** to avoid jank and maintain responsive UIs.

## How the Browser Rendering Pipeline Works

Modern browsers render web pages through three sequential stages. Understanding this pipeline explains why most properties kill performance when animated.

### The Three Stages

1. **Layout** – Calculates element positions, dimensions, and document flow
2. **Paint** – Fills pixels for visual properties like colors and borders
3. **Composite** – GPU combines layers into the final screen image

GPU acceleration occurs only when an animation confines itself to the **composite stage**. Any property touching layout or paint forces the CPU to recalculate and rasterize on every frame.

## Why Transform and Opacity Stay on the GPU

According to [`skills/review-animations/STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/skills/review-animations/STANDARDS.md) at line 112, these two properties are explicitly designated as **composited-only**.

### Transform

The `transform` property applies matrix operations to existing layers:

```css
/* GPU-accelerated movement, scaling, rotation */
.element {
  transform: translate3d(0, 20px, 0) scale(1.1) rotate(5deg);
}

```

The GPU receives pre-built layers and applies coordinate transformations mathematically. No geometry recalculation occurs. The element's size and position in document flow remain unchanged.

### Opacity

The `opacity` property blends layer alpha values during compositing:

```css
/* GPU-accelerated fade effect */
.element {
  opacity: 0.5;
}

```

The GPU simply adjusts a blending coefficient. The painted pixels underneath need no recomputation.

## Properties That Force Layout (Reflow)

Animating these properties triggers complete geometry recalculation, cascading through parent and sibling elements:

- `width` / `height`
- `margin` / `padding`
- `top` / `right` / `bottom` / `left`
- `border-width`

The [`skills/review-animations/SKILL.md`](https://github.com/emilkowalski/skills/blob/main/skills/review-animations/SKILL.md) file at line 35 flags these as **findings** requiring remediation. Line 71 specifically urges developers to "move it to the GPU" by replacing dimension animations with `transform` equivalents.

## Properties That Force Paint

These properties require pixel repainting without layout changes, still CPU-bound:

- `background-color`
- `border-color`
- `box-shadow`
- `outline`

## The Transition: All Trap

The repository explicitly warns against `transition: all` in [`SKILL.md`](https://github.com/emilkowalski/skills/blob/main/SKILL.md) at line 86. This shorthand unintentionally captures off-GPU properties when developers add new styles later.

```css
/* ❌ Dangerous: catches future non-GPU properties */
.element {
  transition: all 200ms ease;
}

/* ✅ Explicit: only what you intend to animate */
.element {
  transition: transform 200ms ease,
              opacity 200ms ease;
}

```

## Practical Refactoring Examples

### Height Animation to Scale Transform

```css
/* ❌ Bad: animates height, forces layout */
.accordion {
  height: 0;
  transition: height 200ms ease-out;
}

.accordion.open {
  height: 200px;
}

/* ✅ Good: uses scaleY, stays on GPU */
.accordion {
  transform: scaleY(0);
  transform-origin: top;
  transition: transform 200ms ease-out;
}

.accordion.open {
  transform: scaleY(1);
}

```

### Slide Animation with Translate

```css
/* ❌ Bad: animates left, forces layout */
.slide {
  position: relative;
  left: -100%;
  transition: left 300ms ease;
}

.slide.visible {
  left: 0;
}

/* ✅ Good: uses translateX, stays on GPU */
.slide {
  transform: translateX(-100%);
  transition: transform 300ms ease;
}

.slide.visible {
  transform: translateX(0);
}

```

### Fade Animation with Opacity

```css
/* ✅ Correct: opacity is GPU-accelerated */
.toast {
  opacity: 0;
  transform: translateY(8px);
  transition: 
    opacity 200ms ease-out,
    transform 200ms ease-out;
}

.toast.visible {
  opacity: 1;
  transform: translateY(0);
}

```

## Framework-Specific Warnings

As noted in [`SKILL.md`](https://github.com/emilkowalski/skills/blob/main/SKILL.md) at line 35, abstracted transforms can still cause problems. Framer Motion's `x`, `y`, and `scale` props compile to CSS transforms but may fallback to non-GPU-friendly implementations under memory pressure. Always verify the actual computed styles in DevTools.

## Performance Targets from the Repository

The [`skills/emil-design-eng/SKILL.md`](https://github.com/emilkowalski/skills/blob/main/skills/emil-design-eng/SKILL.md) file at line 509 establishes these thresholds for maintainable animations:

- **Maximum duration**: 300ms for UI feedback
- **Target frame rate**: 60fps consistently
- **Trigger condition**: 17ms frame budget during heavy main-thread load

GPU-accelerated `transform` and `opacity` meet these targets because they execute independently of JavaScript execution, DOM mutations, and other main-thread work.

## Summary

- **`transform` and `opacity`** are the only CSS properties that skip layout and paint entirely
- **Layout properties** (`width`, `height`, `margin`, `left`, etc.) force expensive geometry recalculation
- **Paint properties** (`background-color`, `border-color`) require CPU pixel rasterization
- **`transition: all`** is an anti-pattern that accidentally animates non-GPU properties
- **Refactor dimension animations** to use `scale` and `translate` inside `transform`
- **Keep animations under 300ms** and verify 60fps in Chrome DevTools Performance panel

## Frequently Asked Questions

### Can any other CSS properties be GPU-accelerated?

No. According to [`STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/STANDARDS.md) in the `emilkowalski/skills` repository, only `transform` and `opacity` are classified as composited-only properties. Some browsers experiment with `filter` acceleration, but cross-browser consistency makes `transform` and `opacity` the only reliable choices for production applications.

### Why does animating `left` feel slower than `translateX`?

`left` triggers layout recalculation for the affected element and potentially its siblings and ancestors. `translateX` operates on an existing compositor layer without touching the layout tree. The visual result appears identical, but `translateX` executes entirely on the GPU while `left` consumes main-thread CPU cycles.

### How do I verify my animation runs on the GPU?

Open Chrome DevTools, enable **Paint flashing** in the Rendering panel, and trigger your animation. Green rectangles indicate repaints (CPU work). GPU-accelerated animations show no paint flashing. Additionally, the **Performance** panel's frame view shows no purple "Layout" or green "Paint" blocks during transform/opacity animations.

### Is `will-change` necessary for GPU acceleration?

Not for `transform` and `opacity` in most cases. Modern browsers automatically promote elements with these properties to their own compositor layers. Explicit `will-change: transform` can help in complex layer management scenarios but should be removed after animation completes to prevent excessive memory consumption from unused layers.