CSS Animations & Keyframes

Deep-dive into CSS animations — transitions, @keyframes, timing functions, 8 production-ready animations, rendering pipeline, and performance optimization with interactive demos.

By Forhad30 min readIntermediateInteractive Demo
CSS Animations & Keyframes

Transitions — The Foundation

Transitions are the simplest way to add motion. They smoothly animate between two states when a property changes — on hover, focus, or class toggle. Understanding transitions is essential before diving into keyframe animations.

Transitions vs Animations

Transitions animate between two states on trigger. Animations run autonomously with keyframes.

🔄 Transitions

  • • Animate between 2 states (A → B)
  • • Require a trigger (hover, focus, class change)
  • • Simple: just add transition property
  • • Best for: hover effects, toggles, state changes

🎬 Animations

  • • Animate through multiple steps (A → B → C → ...)
  • • Run automatically (no trigger needed)
  • • Use @keyframes for complex sequences
  • • Best for: loaders, attention grabbers, storytelling

The 4 Transition Properties

transition-propertyWhich CSS properties to animate (all, width, opacity, transform, etc.)
transition-durationHow long the transition takes (0.3s, 500ms)
transition-timing-functionThe easing curve (ease, linear, ease-in-out, cubic-bezier)
transition-delayWait before starting (0s, 200ms)
/* Shorthand */
.button {
  transition: all 0.3s ease-in-out;
}

/* Longhand */
.button {
  transition-property: background-color, transform;
  transition-duration: 0.3s;
  transition-timing-function: ease-in-out;
  transition-delay: 0s;
}

Timing Functions — Interactive

Duration:0.5s

Constant speed from start to end

linear
ease
ease-in
ease-out
ease-in-out
cubic-bezier

Click "Trigger" to see all easings race side by side

.element {
  transition: transform 0.5s linear;
}
.element:hover {
  transform: translateX(100%);
}

🔑 Key Takeaway: Transitions are the simplest way to add motion to CSS. The timing function controls the acceleration curve. ease-out feels the most natural for UI interactions — fast response, gentle landing.

@keyframes — Multi-Step Animations

While transitions animate between two states, @keyframes let you define animations with multiple steps, complex timing, and autonomous playback. They're the backbone of CSS animation — from loading spinners to page transitions.

@keyframes — Multi-Step Animations

Define named animation sequences with percentage-based stops.

From/To Syntax

@keyframes fadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

Percentage Syntax

@keyframes bounce {
  0%   { transform: translateY(0); }
  50%  { transform: translateY(-30px); }
  100% { transform: translateY(0); }
}

The 8 Animation Properties

animation-name

References a @keyframes block by name

animation-name: slide;
animation-duration

Length of one cycle

animation-duration: 1s;
animation-timing-function

Easing curve per cycle

animation-timing-function: ease-in-out;
animation-delay

Wait before first cycle

animation-delay: 0.5s;
animation-iteration-count

How many times to loop

animation-iteration-count: infinite;
animation-direction

Forward, reverse, or alternate

animation-direction: alternate;
animation-fill-mode

Style before/after animation

animation-fill-mode: forwards;
animation-play-state

Pause or resume

animation-play-state: paused;

Animation Playground

Duration: 1.5s
Direction
Fill Mode
CSS
@keyframes bounce-demo {
  0%   { transform: translateY(0) scale(1); }
  50%  { transform: translateY(-40px) scale(1.1); }
  100% { transform: translateY(0) scale(1); }
}

.element {
  animation: bounce-demo 1.5s ease-in-out
    infinite alternate forwards;
  animation-play-state: running;
}

🔑 Key Takeaway: @keyframes define the animation steps. The animation shorthand combines all 8 properties. Use alternate direction for smooth back-and-forth, forwards fill-mode to keep the final state, and infinite for continuous loops.

8 Essential Production Animations

These are the animations you'll reach for in real projects: fade for reveals, slide for entrances, scale for emphasis, spin for loading, pulse for attention, shake for errors, bounce for playfulness, and shimmer for skeleton screens.

8 Essential CSS Animations

The animations you'll use in 90% of production UIs. Click to preview and copy.

👻
@keyframes fadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.element {
  animation: fadeIn 0.6s ease-out forwards;
}

🔑 Key Takeaway: These 8 animations cover most UI needs: fade for reveals, slide for entrances, scale for emphasis, spin for loading, pulse for attention, shake for errors, bounce for playfulness, and shimmer for skeleton screens.

Animation Performance

Not all CSS properties are equal when it comes to animation performance. Animating width triggers expensive layout recalculation, while transform runs entirely on the GPU. Understanding the rendering pipeline is the key to 60fps animations.

The Rendering Pipeline

Every frame goes through this pipeline. Animating properties higher up the chain is more expensive.

JavaScript

Trigger (requestAnimationFrame, class toggle)

Style

Compute styles for affected elements

Layout

Calculate geometry (width, height, position)

Paint

Fill pixels (colors, shadows, text)

Composite

Combine layers on GPU (transform, opacity)

✅ Best: Composite-Only Animations

Animating transform and opacity skips Layout and Paint entirely — only the GPU Composite step runs. This means 60fps even on slow devices.

transform
GPU-accelerated. Doesn't trigger layout or paint.(translate, scale, rotate, skew)
opacity
GPU-accelerated. Only compositing step, no repaint.(Fade in/out effects)
filter
GPU-composited in most browsers.(blur(), brightness(), drop-shadow())

Performance Tricks

🚀 will-change

Hint to the browser that a property will change, so it can pre-promote the element to its own compositor layer.

.card:hover { will-change: transform; }
/* Remove after animation completes */
.card { will-change: auto; }

⚠️ Don't Overuse will-change

Each will-change element gets its own GPU layer. Too many layers = more memory, more compositing work. Only use it on elements that actually animate.

🎯 prefers-reduced-motion

Respect users who get motion sickness. Always provide a reduced-motion alternative.

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

🔑 Key Takeaway: Only animate transform and opacity for 60fps performance. These skip Layout and Paint, running entirely on the GPU. Use will-change sparingly, and always respect prefers-reduced-motion.