🎞️ CSS Advanced

Animations

⏱ 1 hr2 topicsLive playground
🎯 By the end: You can define a @keyframes animation, run it with the animation property, loop or pause it, and respect users' motion preferences.

Transitions animate a change between two states. Animations go further — they let you script motion through many steps and loop it forever, all without JavaScript. Think loading spinners, a gently pulsing button, a fading-in section. Used with restraint, they add real life to a page.

1@keyframes and the animation property

You build an animation in two parts. First, define the steps with @keyframes, giving the name and what changes at each point (from/to, or percentages):

@keyframes pulse {
  0%   { transform: scale(1); }
  50%  { transform: scale(1.15); }
  100% { transform: scale(1); }
}

Then apply it with the animation shorthand — name, duration, timing, and how many times (or infinite):

.heart {
  animation: pulse 1.2s ease-in-out infinite;
}
A live looping animation
HTML
CSS
Live preview
What's happening: The spinner uses a spin keyframe rotating to 360deg, looped infinitely and linearly. The button uses the pulse keyframes to grow and shrink forever. Change a duration or the scale value and watch the rhythm change.
Key points
  • Define motion steps with @keyframes name { ... } using from/to or percentages.
  • Run it with animation: name duration timing iteration; (use infinite to loop).
  • Animations can run many steps and loop — unlike a transition's single state change.

2Control, restraint and accessibility

A few more controls you'll use:

  • animation-delay — wait before starting.
  • animation-direction: alternate — play forwards then backwards (great for pulses).
  • animation-fill-mode: forwards — keep the final frame after it ends.
  • animation-play-state: paused — pause it (e.g. on hover).
Restraint is the skill. A page where everything moves is exhausting and looks amateur. Animate to guide attention — a spinner that says "loading", a gentle nudge on a call-to-action — not for the sake of it.

Respect reduced motion

Some users get dizzy or nauseous from motion. Always provide a calmer experience for them:

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; }
}
This honours a setting the user has chosen in their operating system — a real, respectful accessibility win, and exactly the kind of detail that separates a thoughtful developer from a careless one.
Key points
  • Control with animation-delay, -direction: alternate, -fill-mode: forwards, -play-state: paused.
  • Animate with restraint — to guide attention, not decorate everything.
  • Honour @media (prefers-reduced-motion: reduce) for users sensitive to motion.

★ Practical: a loading spinner and a nudge

In any playground:

  1. Define a spin keyframe and make a circular spinner loop infinite and linear.
  2. Define a pulse keyframe and apply it to a call-to-action button.
  3. Add animation-direction: alternate to one and see the difference.
  4. Add a prefers-reduced-motion media query that disables the animations.

Ready to test yourself?

Take the short quiz. Score 60% or more to mark this lesson complete.

Start the quiz →

💡 Log in to save your progress and earn the certificate.