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.
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