FrontendJun 20263 min read

Css Transitions vs Keyframes

CSS transitions tween a property between two states when something else changes it; @keyframes choreograph multi-step, looping, self-starting motion. Different jobs — and most people reach for the wrong one.

The short answer

Keyframes over Css Transitions for most cases. Transitions are a one-trick pony: two states, locked to an external trigger.

  • Pick Css Transitions if animating a simple A-to-B state change tied to :hover, :focus, a toggled class, or a data attribute — a button color, a fade on click, a drawer slide. Transitions are two lines and impossible to over-engineer
  • Pick Keyframes if need more than two states, a loop, autoplay with no trigger, or pause/reverse/sequence control — spinners, pulsing badges, attention loops, scripted intros
  • Also consider: Both run on the compositor only when you stick to transform and opacity. Animate width, height, top, or even color and you trigger layout/paint and jank — that's a property problem, not a transitions-vs-keyframes problem. Neither saves you from animating the wrong thing.

— Nice Pick, opinionated tool recommendations

The actual difference

A transition watches a property and tweens it when the value changes — but something else must change it. No :hover, no class toggle, no JS style write means no animation. It is reactive by design and capped at two states: where you were and where you're going. @keyframes is a named timeline you define on its own — 0%, 40%, 100%, as many stops as you like — then attach with the animation property. It can autoplay on load, loop forever, alternate direction, and pause. The mental model that ends the confusion: transitions decorate a state change you already caused; keyframes describe motion that exists independently. That single distinction predicts which one you need before you write a line. Reach for a transition and discover you need a third state, and you're rewriting it as keyframes anyway. Start there if there's any doubt.

Where transitions win

For the boring 80% of UI motion, transitions are flatly better — not because they do more, but because they do less. transition: transform .2s ease on a button, and every :hover, :focus, and toggled class animates for free, with no @keyframes block, no animation-name, no eight-property shorthand to misremember. They interrupt gracefully: hover off mid-animation and the value smoothly reverses from wherever it is, because the transition tracks the live computed value. Keyframes don't do that — interrupt a running animation and it snaps or restarts unless you hand-manage fill modes and play state. Transitions also map cleanly to React/Vue state: toggle a class, the framework owns the trigger, CSS owns the tween. That's why component libraries lean on them. If your animation has exactly two ends and a natural trigger, keyframes is busywork.

Where keyframes win

Anything with a middle. A loading spinner spins forever with no trigger — transitions literally cannot express that, since they need a value change and they never repeat. A toast that slides in, holds, then fades needs three distinct moments on one timeline: trivial in @keyframes, impossible in a transition without chaining JS timeouts like an animal. animation-iteration-count, animation-direction: alternate, animation-delay to stagger a list, and animation-play-state to pause and resume — none have transition equivalents. You also get real orchestration: multiple keyframe animations on one element, each with its own duration and easing. The cost is verbosity and the autoplay footgun — keyframes fire on load whether the element is visible or not, so a 'hidden' element animating offscreen is a classic bug. Power with sharper edges.

The performance truth nobody'll admit

This comparison is mostly a distraction from the question that actually decides whether your animation is smooth: which property are you animating? Both transitions and keyframes hand the work to the same engine. Animate transform and opacity and either one runs on the GPU compositor at 60fps, off the main thread. Animate width, height, margin, top, or box-shadow and both trigger layout or paint every frame, and both jank identically on a mid-tier phone. People blame 'CSS animations are slow' when they chose the wrong property, then 'fix' it by switching syntaxes and wonder why nothing improved. Use will-change sparingly — it's a hint, not a fix, and over-applying it eats memory. The honest hierarchy: pick the right property first, pick transition-vs-keyframes second. Get that backwards and this entire page won't save you.

Quick Comparison

FactorCss TransitionsKeyframes
Number of statesExactly two — start and endUnlimited stops (0%–100%)
Needs an external triggerYes — no trigger, no animationNo — can autoplay on load
Looping / repeatingImpossibleanimation-iteration-count, infinite
Simple hover/toggle ergonomicsTwo lines, interrupts gracefullyVerbose, snaps on interrupt
Compositor performanceGPU on transform/opacityGPU on transform/opacity

The Verdict

Use Css Transitions if: You're animating a simple A-to-B state change tied to :hover, :focus, a toggled class, or a data attribute — a button color, a fade on click, a drawer slide. Transitions are two lines and impossible to over-engineer.

Use Keyframes if: You need more than two states, a loop, autoplay with no trigger, or pause/reverse/sequence control — spinners, pulsing badges, attention loops, scripted intros.

Consider: Both run on the compositor only when you stick to transform and opacity. Animate width, height, top, or even color and you trigger layout/paint and jank — that's a property problem, not a transitions-vs-keyframes problem. Neither saves you from animating the wrong thing.

Css Transitions vs Keyframes: FAQ

Is Css Transitions or Keyframes better?

Keyframes is the Nice Pick. Transitions are a one-trick pony: two states, locked to an external trigger. @keyframes does everything a transition does (a two-stop keyframe IS a transition) plus multi-step sequencing, looping, autoplay, and pause/reverse — strictly the larger toolset. If you learn one, learn keyframes.

When should you use Css Transitions?

You're animating a simple A-to-B state change tied to :hover, :focus, a toggled class, or a data attribute — a button color, a fade on click, a drawer slide. Transitions are two lines and impossible to over-engineer.

When should you use Keyframes?

You need more than two states, a loop, autoplay with no trigger, or pause/reverse/sequence control — spinners, pulsing badges, attention loops, scripted intros.

What's the main difference between Css Transitions and Keyframes?

CSS transitions tween a property between two states when something else changes it; @keyframes choreograph multi-step, looping, self-starting motion. Different jobs — and most people reach for the wrong one.

How do Css Transitions and Keyframes compare on number of states?

Css Transitions: Exactly two — start and end. Keyframes: Unlimited stops (0%–100%). Keyframes wins here.

Are there alternatives to consider beyond Css Transitions and Keyframes?

Both run on the compositor only when you stick to transform and opacity. Animate width, height, top, or even color and you trigger layout/paint and jank — that's a property problem, not a transitions-vs-keyframes problem. Neither saves you from animating the wrong thing.

🧊
The Bottom Line
Keyframes wins

Transitions are a one-trick pony: two states, locked to an external trigger. @keyframes does everything a transition does (a two-stop keyframe IS a transition) plus multi-step sequencing, looping, autoplay, and pause/reverse — strictly the larger toolset. If you learn one, learn keyframes.

Related Comparisons

Disagree? nice@nicepick.dev