Skip to main content

Animations & Transitions

Transitions

.btn {
background: #3b82f6;
transition: background 200ms ease-out, transform 150ms ease-out;
}

.btn:hover {
background: #2563eb;
transform: translateY(-2px);
}

What Can Be Transitioned Performantly?

Only transform and opacity are GPU-composited (no layout/paint cost). Avoid transitioning width, height, top, left, margin, padding.

/* Bad — triggers layout */
.box { transition: width 300ms; }

/* Good — GPU composited */
.box { transition: transform 300ms; }

Keyframe Animations

@keyframes slide-in {
from {
opacity: 0;
transform: translateX(-100%);
}
to {
opacity: 1;
transform: translateX(0);
}
}

.panel {
animation: slide-in 300ms ease-out forwards;
}

animation-fill-mode

ValueBehavior
noneReverts to initial styles after animation
forwardsRetains final keyframe styles
backwardsApplies first keyframe styles during delay
bothCombines forwards + backwards

will-change

Hints the browser to prepare GPU layers ahead of time:

.animated-card {
will-change: transform, opacity;
}

Use sparingly — excessive will-change increases memory consumption. Remove it after animation completes if possible.

Stacking Context & z-index

A new stacking context is created by:

  • position: relative/absolute/fixed/sticky + z-index value
  • opacity less than 1
  • transform, filter, perspective, clip-path
  • isolation: isolate
  • will-change
/* Create an explicit stacking context to contain z-index */
.modal-overlay {
isolation: isolate;
}

View Transitions API (Modern)

Animate between DOM states or page navigations:

::view-transition-old(root) {
animation: fade-out 200ms ease-out;
}

::view-transition-new(root) {
animation: fade-in 200ms ease-in;
}
document.startViewTransition(() => {
// Update DOM here
});