CSS Animation

Animations & Transitions

CSS transitions and keyframes bring interfaces to life with no JavaScript. Animate the right properties and motion stays smooth and accessible.

intermediate14 min readUpdated Sep 15, 2026
pulse.css
css
/* pulse.css */
@keyframes pulse {
  0%, 100% { transform: scale(1); opacity: 1; }
  50% { transform: scale(1.05); opacity: 0.8; }
}

.badge {
  animation: pulse 2s ease-in-out infinite;
  transition: transform 150ms ease;
}

.badge:hover {
  transform: scale(1.1);
}
State change
transition
Sequence
@keyframes + animation
Movement
transform
Smoothness
timing-function
Performance
transform and opacity
Accessibility
prefers-reduced-motion

Why it matters

Why motion matters

Clear feedback

Motion shows that something changed, which makes interfaces feel responsive and understandable.

Cheap when done right

Animating transform and opacity runs on the compositor, so it stays smooth without layout or paint.

Respects users

Honouring reduced-motion preferences keeps motion from causing discomfort.

The big picture

The three tools of CSS motion

Transitions for state changes, keyframes for sequences, and transforms for cheap, compositor-friendly movement.

Transitions

React

Smooth changes between two states, triggered by hover, focus or a class change.

Keyframes

Sequence

Multi-step animations with control over each stage and iteration.

Transforms

Move

translate, scale and rotate change appearance without affecting layout.

CSS motion at a glance

The core techniques

transition

Specify property, duration, timing and delay for state changes.

transform

translate, scale, rotate and skew without triggering layout.

@keyframes

Define named animations with percentages and iterate them.

Timing functions

ease, linear, cubic-bezier and steps control the feel.

Performance

Stick to transform and opacity; avoid layout properties.

Reduced motion

Disable or simplify motion when the user asks.

A short history

From hover fades to view transitions

  1. 2009

    Transitions and transforms

    CSS gains smooth state changes and 2D/3D transforms.

    09
  2. 2012

    CSS animations

    Keyframes make multi-step animations declarative.

    12
  3. 2015

    Hardware acceleration

    Compositor-friendly transforms become the performance norm.

    15
  4. 2023

    View Transitions API

    Animated transitions between page and DOM states become native.

    23
  5. Today

    Motion with restraint

    Accessibility and performance guide how motion is used.

    Today

The complete guide

Animations & Transitions: Everything you need to know

Why motion matters

Motion is communication. A button that eases into its pressed state, a panel that slides into view and a list that reorders smoothly all tell the user what just happened. Done well, motion makes an interface feel responsive and polished. Done badly, it distracts and frustrates.

CSS gives you three tools: transitions for state changes, keyframes for sequences and transforms for movement. Master those and you rarely need JavaScript for everyday animation.

Transitions

A transition smoothly interpolates between two states and runs when a property changes.

/* button.css */
.button {
  background: #2563eb;
  transform: translateZ(0);
  transition: background-color 150ms ease, transform 150ms ease;
}

.button:hover {
  background: #3b82f6;
  transform: translateY(-1px);
}

.button:active {
  transform: translateY(0);
}

The shorthand takes the property, duration, timing function and optional delay. Transitions need a trigger: :hover, :focus, :checked, a class change from JavaScript or a media query. Keep durations short — 150 to 300 milliseconds is usually enough for feedback.

Transforms

Transforms change how an element looks without affecting the layout of others, which is why they are cheap to animate.

/* transform.css */
.move { transform: translateX(24px); }
.grow { transform: scale(1.1); }
.turn { transform: rotate(45deg); }
.skew { transform: skewX(-10deg); }

.combo {
  transform: translateY(-4px) scale(1.02) rotate(-1deg);
}

translate, scale and rotate can run on the compositor, so they stay smooth even under load. Animating width, height, top or margin instead forces the browser to recalculate layout on every frame.

Keyframes

For multi-step or looping animation, use @keyframes and animation.

/* spinner.css */
@keyframes spin {
  to { transform: rotate(360deg); }
}

.spinner {
  animation: spin 800ms linear infinite;
}

@keyframes fade-up {
  from { opacity: 0; transform: translateY(12px); }
  to { opacity: 1; transform: translateY(0); }
}

.enter {
  animation: fade-up 300ms ease-out both;
}

The animation shorthand sets name, duration, timing, delay, iteration count, direction and fill mode. both is handy for entrance animations because it applies the first and last keyframe states.

Timing functions

The timing function controls the feel. Easing is what makes motion look natural rather than mechanical.

/* easing.css */
.linear { transition-timing-function: linear; }
.ease-out { transition-timing-function: cubic-bezier(0.22, 1, 0.36, 1); }
.bounce { transition-timing-function: cubic-bezier(0.68, -0.55, 0.27, 1.55); }
  • ease-out for elements entering the screen, so they decelerate.
  • ease-in for elements leaving.
  • ease-in-out for movement between two visible states.
  • steps() for frame-like effects such as typing or sprite animation.

Performance

The rule is simple: animate transform and opacity. Those can be handled by the compositor, skipping layout and paint. Anything that changes geometry triggers layout, and anything that changes colour or shadow triggers paint.

/* hint.css */
.animated {
  will-change: transform;
}

will-change hints that an element is about to animate, so the browser can promote it to its own layer. Use it sparingly and remove it once the animation finishes; too many promoted layers waste memory. See the Browsers & Rendering guide for why.

Accessibility and reduced motion

Some users experience dizziness or nausea from motion, and the operating system exposes that preference.

/* reduced.css */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

A blanket rule like this is a safe baseline. For a more nuanced approach, replace large movement with a simple fade. Never convey meaning through motion alone.

View transitions

The View Transitions API animates between two DOM states or pages natively.

// navigate.js
document.startViewTransition(() => {
  updateTheDOM();
});

The browser snapshots the old and new states and animates between them, and you control the effect with CSS pseudo-elements. It is ideal for page navigation and list reordering. Provide a plain fallback for browsers that do not support it.

Patterns

  • Hover and focus feedback. Short transitions on colour and transform.
  • Entrance animations. Fade and slide in with both fill mode.
  • Staggered lists. Delay each item slightly, often set with a CSS variable and inline style.
  • Skeletons and spinners. Looping keyframes to signal loading.
  • Accordions and drawers. Transition height via grid-template-rows from 0fr to 1fr, which animates cleanly.

Best practices

  • Animate transform and opacity; avoid layout properties.
  • Keep durations short: 150–300ms for feedback, longer for emphasis.
  • Use ease-out for entrances and ease-in for exits.
  • Respect prefers-reduced-motion.
  • Use will-change sparingly and clean up after animating.
  • Prefer CSS for simple cases and JavaScript for complex sequences.
  • Test on low-powered devices, not just a fast desktop.

Common mistakes

  • Animating width, height or top and causing jank.
  • Leaving will-change on permanently and wasting memory.
  • Long, slow animations that make the UI feel sluggish.
  • Ignoring reduced-motion preferences.
  • Infinite motion that distracts from the content.
  • Relying on animation to convey essential information.

Where to go next

CSS motion covers most of what interfaces need. When you want timelines, scroll-driven storytelling or precise control, move on to the Advanced Animation guide. Understand the cost with Browsers & Rendering, keep it fast with Web Performance, and start from CSS fundamentals.

Choosing what to animate

transform and opacity can run on the compositor. Animating width or top triggers layout on every frame and janks.

Prefer
.card {
  transition: transform 200ms ease, opacity 200ms ease;
}
.card:hover {
  transform: translateY(-4px);
}
Avoid
.card {
  transition: top 200ms ease, width 200ms ease;
}
.card:hover {
  top: -4px;
  width: 320px;
}

Respecting motion preferences

Users who ask for reduced motion should get a simpler or instant experience, not a nauseating one.

Prefer
.panel {
  transition: transform 300ms ease;
}

@media (prefers-reduced-motion: reduce) {
  .panel {
    transition: opacity 150ms ease;
  }
}
Avoid
.panel {
  animation: slide 600ms ease infinite;
}
/* ignores the user's
   motion preference */

FAQ

Frequently asked questions

Keep learning

Related topics from the roadmap.

$ start learning

Ready to start learning Animations & Transitions?

Our interactive tutorial walks you through Animations & Transitions step by step — with quizzes and real code you can run in the browser.