Animations vs. Transitions: What's the Difference?

Before diving in, it's worth clarifying the two main CSS motion tools:

FeatureTransitionsAnimations (@keyframes)
TriggerState change (e.g., hover)Can auto-play or loop
Control pointsStart and end onlyMultiple keyframe stops
LoopingNoYes
ComplexitySimpleComplex multi-step motion

Use transitions for simple, state-driven changes (hover, focus). Use @keyframes animations for anything multi-step, looping, or auto-triggered.

Anatomy of a Keyframe Animation

A CSS animation is made up of two parts: the @keyframes rule (defining the steps) and the animation property (applying it to an element).

@keyframes slide-in {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.card {
  animation: slide-in 0.4s ease-out forwards;
}

Using Percentage Steps

You're not limited to from and to. Use percentage values to define complex motion paths:

@keyframes bounce {
  0%   { transform: translateY(0); }
  40%  { transform: translateY(-30px); }
  60%  { transform: translateY(-15px); }
  80%  { transform: translateY(-5px); }
  100% { transform: translateY(0); }
}

Key Animation Properties

  • animation-name: The @keyframes rule to use.
  • animation-duration: How long one cycle takes (e.g., 0.5s).
  • animation-timing-function: Easing curve (ease, linear, cubic-bezier()).
  • animation-delay: Wait before starting.
  • animation-iteration-count: Number of cycles, or infinite.
  • animation-direction: normal, reverse, alternate.
  • animation-fill-mode: What styles apply before/after (forwards, backwards, both).

Performance: Stick to Compositor-Friendly Properties

Not all CSS properties animate equally. For smooth 60fps animations, only animate these properties:

  • transform (translate, scale, rotate)
  • opacity

Animating width, height, top, left, or background-color forces the browser to recalculate layout or repaint pixels — both expensive operations. Always prefer transform: translateX() over changing left.

Respecting User Preferences

Some users experience discomfort or motion sickness from animations. Always wrap non-essential animations in a media query:

@media (prefers-reduced-motion: no-preference) {
  .card {
    animation: slide-in 0.4s ease-out forwards;
  }
}

This ensures your animations only run for users who haven't opted out of motion in their OS settings.

Staggered Animations with animation-delay

A classic UI pattern is staggering a list of items so they animate in one by one. Use CSS custom properties or nth-child selectors to vary the delay:

.list-item:nth-child(1) { animation-delay: 0s; }
.list-item:nth-child(2) { animation-delay: 0.1s; }
.list-item:nth-child(3) { animation-delay: 0.2s; }

Conclusion

CSS keyframe animations give you expressive control over motion in the browser — without a single line of JavaScript. Master the basics, respect performance constraints, and always keep accessibility in mind. Motion, used thoughtfully, transforms a flat UI into a living, breathing experience.