CSS transition vs animation: which do I need?

Short answer

Use a transition when a property changes because of a state like :hover or a class toggle. Use an animation when the motion should run by itself, repeat, or pass through intermediate steps.

#Transition

css
.button {
  background: var(--brand-500);
  transition: background 0.2s ease, transform 0.2s ease;
}
.button:hover {
  background: var(--brand-600);
  transform: translateY(-2px);
}

Two states, and the browser interpolates between them.

#Animation

css
@keyframes pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.4; }
}

.loading { animation: pulse 1.5s ease-in-out infinite; }

No state change required, and it can repeat or pass through midpoints.

#Never transition "all"

css
transition: all 0.3s;      /* avoid */

It also animates layout properties, forcing the browser to recompute geometry every frame — and it will animate properties you did not intend, including ones added later. Name what you change.

#Only two properties are cheap

transform and opacity are handled by the compositor and do not trigger layout or paint. Everything else — width, height, top, margin, box-shadow — costs work on every frame.

Animate position with transform: translate(), not top/left. Animate size with transform: scale() where you can.

#Honour reduced motion

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

Some people get genuinely motion sick from large transitions and parallax. Five lines, not optional.

#Timing that feels right

Most UI transitions want 150–250ms. Under 100ms reads as instant; over 400ms feels sluggish. ease-out suits things entering, ease-in suits things leaving.