Skip to content
beginner Phase 12 · Transitions and Animations

CSS Animations and Keyframes

Drive continuous and state-based animations with plain CSS.

30m
0 problems
Topic Progress 0%

Animate a loading indicator without tying it to component rerenders

Keyframes describe a timeline, not a pair of states

A CSS transition interpolates between a before state and an after state when a property changes. A keyframe animation describes one or more stages over a timeline and can run even when Vue state does not keep changing. That makes it useful for a spinner, a pulsing indicator, or a short attention cue. Keep the animation in CSS and let Vue control whether the element exists or which state class it has. This separation avoids a JavaScript timer that updates component state dozens of times per second.

A keyframe rule names the stages. The animation declaration then selects the name, duration, timing curve, iteration count, direction, fill mode, and delay. For example, a spinner can animate a rotation transform over one second and repeat indefinitely while a request is pending. A short entrance accent can animate opacity and transform once, then hold its final appearance with forwards fill mode. Each property has a purpose: duration controls total time, timing controls the pace, iteration count controls repetitions, and fill mode determines how styles behave outside the active interval.

A component can bind a class from a ref that tracks a real request state. When pending becomes true, render the indicator with a loading class; when the request settles, remove it. The animation does not fetch data or decide whether an operation succeeded. The state model remains responsible for request start, success, and failure. If the indicator is only decorative, include a separate text label or status region so users can identify what is happening without interpreting motion.

Keyframes can use from and to for the endpoints or percentage stops for intermediate stages. A three-stage pulse might start at low opacity, rise at 40 percent, and settle back before the end. Intermediate values let you control anticipation or overshoot, but too many stops make the effect difficult to tune. Prefer a small number of deliberate stages. The animation timing function applies between keyframe stops; a linear function is often right for continuous rotation, while an easing curve can make a one-shot entrance feel less mechanical.

Animation properties can be composed in a shorthand, but explicit longhand declarations are easier to review when several effects differ. Multiple animations can be comma-separated, with corresponding duration and timing values. A common bug is listing two animation names but only one duration and assuming both share all settings. Check computed style to see how the comma-separated lists pair. Also verify that another selector does not override animation-name or set animation to none.

Animations can affect layout, paint, and compositing differently. Transform and opacity are often cheaper because browsers can composite them without recalculating document flow. Animating width, height, top, or left may cause layout on each frame and move neighboring content. Use those properties only when the layout effect is intentional and the affected area is small. A large blur or shadow can also be expensive. Profile the real page if many elements animate at once; a smooth isolated demo does not guarantee smooth scrolling on a low-powered device.

CSS keyframes do not understand application state. An infinite animation will continue until the element is removed or the animation is disabled. Tie indefinite motion to a pending state and ensure every request path reaches success, error, or cancellation. A stuck spinner often signals missing error-state handling rather than a CSS defect. A one-shot effect can use a finite iteration count. Avoid replaying it on every unrelated rerender; class changes or element recreation should be intentional.

Interviewers often ask when you choose keyframes over transitions. Explain that transitions respond to a change between two states, while keyframes define a timeline that may repeat or include several stages. Then discuss what Vue controls, which CSS properties animate, and how you respect reduced motion. That answer ties the mechanism to real component behavior.

Tie a progress pulse to a real pending state

Make the visual effect follow request state

Build a component whose pending ref becomes true when a request begins and false in a finally block after success or failure. Render a small status indicator only while pending. Its keyframe can rotate or pulse continuously, but the text should say that work is in progress. If the request fails, replace the pending indicator with an error message and a retry action. Do not leave an infinite animation running after rejection, cancellation, or navigation.

For a progress bar, distinguish indeterminate from measured progress. If the server provides no percentage, use a looping visual cue but do not imply a precise completion estimate. If progress is known, bind a CSS custom property or width to the measured value and use a transition for movement between reported states. Keyframes and transitions can coexist: keyframes provide a subtle shimmer inside the bar, while the transition updates its actual measured length. Keep the real value available to assistive technology with an appropriate progress element and accessible label.

Restart behavior deserves an explicit decision. Removing and reinserting an element restarts its animation. Toggling a class can also restart it when animation-name changes, but changing unrelated style properties may not. If a one-shot animation must replay on repeated events, use a reactive key that changes for each event or remove and re-add the class after the current frame. Avoid arbitrary timeouts that race the CSS duration. When code needs to respond to animation completion, listen for the animationend event and account for cancellation and reduced-motion rules that may shorten or remove the animation.

Test at least four states: initial idle, pending, success, and failure. Trigger a quick retry before the previous request resolves and confirm the indicator reflects the latest request rather than an older response. If the component unmounts during a request, cancel it when possible or guard against stale completion. A CSS animation does not cancel network work. Make the data operation's lifecycle and the visual lifecycle agree without making CSS the source of truth.

Use developer tools to inspect the computed animation name, duration, iteration count, and play state. If nothing moves, check that the keyframe name matches the animation declaration and that the element has the expected class. Confirm the animated property has different values at the relevant stops; keyframes that keep the same transform cannot produce visible motion. Check reduced-motion styles and browser support before concluding Vue failed to apply a class. Animation events bubble, so filter events when nested elements also animate.

A meaningful progress cue should not cause layout shifts. Reserve its space or position it in a stable region so the page does not jump when the request starts. For a button spinner, preserve button width and label alignment. If replacing text changes geometry, keep a hidden label or fixed-size icon slot. Repeated movement near primary content can distract, so use small amplitude and a calm duration. If the operation takes long enough to need feedback, pair motion with elapsed-time guidance or a cancel action where appropriate.

Add a reduced-motion branch for nonessential movement. The media preference can remove rotation or make a pulse static, but preserve the label and semantic state. In tests, emulate reduced motion and ensure the component still communicates pending status. A user should not need to watch an animation to know whether a save completed.

For practice, implement a pulsing status dot, then replace it with a rotating indicator and compare readability. Measure whether the animation shifts layout or causes excessive paint. Change one property at a time and inspect the timeline. The goal is not maximum animation complexity; it is to make the current request state legible with a modest visual cue.

Choose keyframes for timelines and transitions for state changes

Pick an animation model that matches the interaction

Use a keyframe animation when an effect has a defined timeline, several stages, or repetition independent of a property change. Use a transition when a state change should interpolate between two values, such as a panel opening or a button becoming disabled. A keyframe effect can run on a static element without any further Vue updates. A transition needs a change in computed styles or element presence. This distinction helps avoid adding reactive state just to drive a decorative loop.

CSS is usually the right tool for simple motion because the browser owns frame scheduling and the effect is declarative. JavaScript animation APIs or a library can be appropriate for sequencing multiple elements, interruptible timelines, physics-based spring motion, or synchronizing with other imperative work. Vue's JavaScript transition hooks are useful when DOM entry and removal must be coordinated with an external animation system. Avoid splitting ownership: if CSS and JavaScript both control duration, cancellation can leave a node mounted or remove it too early.

Infinite animation has a user and performance cost. A spinner should represent an operation that is actually pending and should stop when the operation ends. A decorative loop should be subtle, pause when offscreen if appropriate, and not compete with reading. Many simultaneously animated elements can consume battery and make the page feel busy. Prefer transform and opacity, keep the number of moving elements small, and profile under realistic conditions. Do not add will-change to every animated node; it can reserve extra compositor memory and should only be used after a measured need.

Animation fill mode can preserve an endpoint after a finite effect, but it can also create styles that seem to remain after the class is removed if the stylesheet still applies the animation. Make the final state explicit in the base class where possible. Direction and iteration count can create alternate or reverse motion, but repeated oscillation is not always clearer than a simple one-way effect. Use animation delay sparingly because a delayed response may look like a broken control.

Respect reduced motion. The prefers-reduced-motion media query lets the stylesheet reduce or disable nonessential motion. Components should still communicate state through text, shape, or color and not rely exclusively on movement. Consider whether an animation flashes or has large movement; short duration alone does not guarantee comfort. Test keyboard and screen-reader interaction independently because CSS visibility does not define semantic availability.

A Vue component should not use a CSS animation to represent a server-side fact it cannot know. A progress animation that implies a fixed percentage when work is indeterminate can mislead. A success flourish should only run after the server confirms success. If the animation is interrupted by navigation, decide whether it should stop immediately or complete in a shared shell. This is product behavior, not a property that CSS can infer.

In an interview, compare keyframes, transitions, and JavaScript animation in terms of timeline complexity, state changes, and cancellation. Give a concrete example such as a repeating pending indicator versus an accordion opening. Mention performance properties, reduced motion, and how a Vue ref controls whether the effect runs. A concise decision tied to interaction quality is stronger than listing animation shorthand fields.

A review checklist is simple: identify whether the effect is state-driven or timeline-driven; choose properties that avoid unnecessary layout; define a finite or state-bound lifetime; and preserve a non-motion cue. Confirm the animation stops on error and unmount, and consider what happens on rapid retries. If the effect does not make the current state easier to understand, remove it. CSS animation is a tool for feedback, not a substitute for request handling or accessible status design.

Quiz

1. What is a key distinction between a CSS transition and a keyframe animation?

Question 1 options

2. How should an indefinite loading animation be controlled?

Question 2 options

3. Which properties are commonly preferable for smooth animation?

Question 3 options

4. What must remain clear when reduced motion disables a decorative animation?

Question 4 options

Flashcards

Question

When are keyframes a better fit than a transition?

Answer

For a timeline with multiple stages or repetition that does not depend on a style changing between two states.

Question

How should an infinite loading animation stop?

Answer

Bind it to real pending state and stop it when the operation succeeds, fails, or is cancelled.

Question

Why prefer transform and opacity for many UI effects?

Answer

They can often be composited without triggering layout on every frame.

Question

What should reduced-motion styling preserve?

Answer

The meaning and accessible communication of the component state, even if movement is removed.

Question

What is a common keyframe debugging check?

Answer

Confirm that the class applies, the animation name matches, and keyframes change the animated property.

Revision Notes

Key Takeaways

  • 1. Keyframes describe a timeline; transitions interpolate between two states after a style change.
  • 2. Let Vue state decide whether an animation is active, and let CSS render the effect.
  • 3. Tie infinite motion to a real pending lifecycle and stop it on every settled path.
  • 4. Prefer transform and opacity when they achieve the effect, and profile costly motion.
  • 5. Reduced-motion users still need a clear non-motion indication of state.

Interview Tips

  • • Compare keyframes and transitions using one repeating effect and one two-state interaction.
  • • Explain how a Vue ref controls the animation lifetime without driving every frame.
  • • Mention layout cost, cancellation, and why an infinite spinner must reflect real work.
  • • Include reduced motion and accessible status in your design decision.

Cheat Sheet

CSS Animations and Keyframes Cheat Sheet

Phase: Transitions and Animations | Level: beginner

Key points:

  • Keyframe rules define intermediate animation states between from and to percentages.
  • The animation shorthand composes name, duration, timing function, and iteration count.
  • Transform-based animations run on the compositor and avoid layout thrashing.
  • The prefers-reduced-motion media query lets users opt out of non-essential movement.

Tags: vue, css, animation

Continue Learning