Stockio

CSS Transition vs Animation: When to Use Keyframes

Choose CSS transitions or keyframes for each motion task, handle interrupted states, and build effects that stay predictable across input methods and reduced-motion settings.

By Aiko Tanaka

Motion Designer ·

On this page

A drawer that follows its open state and a decorative pulse that repeats forever need different animation models. Choosing the wrong one often produces extra classes, fragile event listeners, and visual states that disagree with the application. CSS offers both transitions and keyframes because they solve different scheduling problems.

Start with the state change

A transition interpolates when a computed property changes. A keyframe animation follows an authored timeline after its animation applies. Use the box shadow generator to create two elevation endpoints for a demonstration, then keep those shadows static while comparing how each timing model moves the element between positions. The tool defines appearance; CSS supplies motion.

Ask whether the effect has a meaningful destination or a meaningful sequence. Opening a panel has a destination. A three-stage attention sequence has an authored progression. This distinction is more useful than deciding based on whether the effect looks simple or complex.

Write down the resting state before introducing either mechanism. A component should remain understandable when animation is unavailable, disabled, or interrupted. Motion is a path between valid states, not the only place where a valid state exists.

Use transitions for reversible destinations

Transitions work well when CSS can describe both endpoints through a class, attribute, or pseudo-class. Declare the transition on the base selector so it applies in both directions. Putting it only on the active state commonly makes the return journey snap.

.panel {
opacity: 0;
transform: translateY(8px);
transition: opacity 160ms ease-out, transform 200ms ease-out;
pointer-events: none;
}
.panel[data-open="true"] {
opacity: 1;
transform: translateY(0);
pointer-events: auto;
}
@media (prefers-reduced-motion: reduce) {
.panel { transition: none; }
}

This example demonstrates visual interpolation, not a complete disclosure implementation. Closed content also needs appropriate focus and visibility handling. Opacity alone does not remove descendants from keyboard navigation or the accessibility tree. Handle those concerns in the component's semantic state rather than assuming the animation will do it.

The important benefit is interruption continuity. If the open state changes halfway through, a transition can move from the currently interpolated value toward the new destination. Exact reversal timing follows transition rules, so inspect rapid toggles rather than assuming every reversal lasts the full declared duration.

Prefer explicit property lists to transition: all. A future spacing or color change should not silently inherit motion. The MDN transition guide explains the underlying interpolation model and transition events.

Use keyframes for an authored sequence

Keyframes are appropriate when the intermediate poses matter: a progress indicator rotating, an illustration assembling, or an onboarding demonstration playing several stages. They can include delays, iteration counts, and direction changes without creating a chain of state classes.

@keyframes beacon {
0%, 100% { transform: scale(1); opacity: .65; }
50% { transform: scale(1.12); opacity: 1; }
}
.beacon[data-running="true"] {
animation: beacon 1200ms ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
.beacon[data-running="true"] { animation: none; }
}

Here, iteration is part of the design. It would be awkward to alternate classes using a timer just to recreate the same loop. However, indefinite movement should have a reason and may require a pause mechanism depending on context and accessibility requirements. A decorative effect does not become essential merely because it expresses brand personality.

Do not confuse animation-fill-mode: forwards with application state. Fill mode retains an animation's visual influence after playback; it does not update a DOM attribute, save user intent, or guarantee that a later stylesheet rule behaves as expected. Prefer a real final class when the finished state belongs to the component.

For terminology and playback options, consult MDN's CSS animations documentation. Avoid combining multiple animations that all write the same transform unless their composition is deliberate.

Handle timing, ownership, and replay

A common bug comes from letting a transition and a keyframe effect control the same property at the same time. Establish property ownership: a wrapper can manage position while its child manages rotation. This makes transforms easier to reason about and avoids depending on subtle cascade and animation composition behavior.

For a replayable entrance, decide what replay means. Removing and immediately reapplying the same class may not restart the animation because the browser can observe only the final style state. Use a controlled remount when appropriate, separate rendering updates, or the Web Animations API when explicit playback control is a core requirement. Do not scatter forced layout reads through event handlers just to restart decorative effects.

Treat completion events as notifications, not guaranteed business logic. A removed element, canceled animation, or reduced-motion stylesheet can change whether the expected event occurs. Save data, enable controls, and update navigation independently of a fade finishing.

Start around 150–250 milliseconds for small state transitions as an experiment, then judge distance, interruption, and perceived responsiveness. These are tuning ranges, not universal usability laws. Longer travel often needs more time, but reducing travel can be better than slowing the interface.

For visual context, review soft shadow techniques. Keep elevation design separate from the decision about which animation model should drive movement.

Verify the behavior, not only the preview

Test a deliberate state matrix: closed to open, open to closed, rapid reversal, component removal, and preference changes. Use keyboard activation as well as pointer input. A hover-only preview can hide event and focus problems that appear immediately in a real application.

Inspect performance with representative content. Transform and opacity often avoid layout work, but they are not a promise of zero rendering cost. Large surfaces, filters, and excessive composited layers can still be expensive. The web.dev animation guide provides a useful rendering-oriented checklist.

Review the reduced-motion path as a designed experience. Preserve status, order, and feedback without requiring travel or looping. A short dissolve may be acceptable for some users, but removing unnecessary movement entirely is a dependable starting point. The accessibility guide supplies broader context without replacing manual motion testing.

Finally, document which state owns each effect and why. A future maintainer should be able to change duration without learning an undocumented chain of timers. Predictability is the strongest reason to select one animation model over another.

Key takeaways

  • Choose destinations with transitions and authored sequences with keyframes.
  • Keep semantic state independent of animation completion.
  • Assign each animated property a clear owner.
  • Test reversal, removal, replay, and reduced motion before release.
Featured sponsor

Reach designers & developers at work

Put your product next to the tools people use every day. One sponsor per placement, no tracking pixels.

Become a sponsor

Keep reading

Related articles

More in Motion & Animation
Motion & Animation

12 Best CSS Animation Generators and Resources

Compare twelve CSS animation references, visual generators and libraries, from easing curve playgrounds to ready-made effects, and find a sensible fit for your web project.

Includes: Box shadowsAiko TanakaAiko Tanaka
Motion & Animation

@starting-style: Animate Dialogs and Popovers in CSS

Create reliable entry and exit transitions for native dialogs and popovers, including discrete display changes, top-layer behavior, fallbacks, and motion preferences.

Includes: Box shadowsAiko TanakaAiko Tanaka
Motion & Animation

Micro-Interactions in UX: Small Details That Matter

Design responsive button, form, and save-state feedback with accessible motion, clear status messages, and a repeatable micro-interaction test plan.

Includes: Box shadowsAiko TanakaAiko Tanaka
Motion & Animation

CSS Hover Effects for Cards and Buttons: Tasteful Defaults

Build restrained hover effects that clarify clickable cards and buttons, with practical CSS timings, keyboard states, touch fallbacks, and reduced-motion rules.

Includes: Box shadowsAiko TanakaAiko Tanaka
HTML & CSS

12 Best CSS Generators That Save Hours

Create gradients, shadows, layouts, and other CSS faster with twelve practical generators, plus advice on checking the code and adapting it to your own design.

Includes: Box shadowsJonah WeissJonah Weiss
UI Design

15 Best Free UI Kits for Figma

Explore fifteen useful free Figma UI kits for websites, apps, and prototypes, with a quick guide to choosing a kit that suits your project and avoids unnecessary setup.

Includes: Box shadowsTheo OkaforTheo Okafor