CSS: Animations

Create multi-step animations that run automatically using @keyframes.

@keyframes Rule

@keyframes defines the steps of an animation. You give it a name and describe what the element should look like at different points, the browser fills in the movement between each step automatically.

@keyframes

@keyframes is defined separately from the element. You give it a name, then apply that name to an element with animation-name. The same keyframes can be reused on many elements.

  • from, the starting state of the animation (same as 0%)
  • to, the ending state of the animation (same as 100%)
  • 0%, 50%, 100%, percentage steps for multi-stage animations
  • The name given to @keyframes is referenced by animation-name on the element
  • You can define as many steps as needed between 0% and 100%

@keyframes

The box slides in from the left using a simple from/to keyframe.

animation-name and animation-duration

animation-name links an element to a set of @keyframes by name. animation-duration sets how long one cycle of the animation takes. Both are required for the animation to play.

animation-name and animation-duration

Without animation-duration, the animation plays at 0s and is invisible. These two properties are the minimum required to run an animation.

  • animation-name: slide-in, applies the @keyframes named slide-in to this element
  • animation-name: none, disables any running animation
  • animation-duration: 0.5s, one cycle of the animation takes 0.5 seconds
  • Duration uses the same s and ms units as transition-duration
  • The name is case-sensitive and must match the @keyframes name exactly

animation-name + animation-duration

A circle pulses continuously using the named keyframes.

animation-timing-function

animation-timing-function controls the speed curve of the animation, the same values as transition-timing-function. It can also be set inside a specific keyframe step to change the curve between steps.

animation-timing-function

The timing function can be placed on the element (applies to all steps) or inside a specific keyframe (applies only from that step to the next).

  • ease, slow start and end, fast middle (default)
  • linear, constant speed; best for continuous loops like spinners
  • ease-in-out, smooth acceleration and deceleration
  • steps(n), jumps between n discrete frames; useful for sprite animations
  • Setting it inside a keyframe step overrides the element-level value for that step only

animation-timing-function: linear

A spinner uses linear so it rotates at a constant speed with no easing.

animation-delay

animation-delay sets how long the browser waits before starting the animation. A negative value starts the animation immediately but partway through its cycle.

animation-delay

Use staggered delays on a list of elements to make them animate in one after another. A negative delay is useful to offset looping animations so they don't all start in sync.

  • animation-delay: 0.5s, wait 500ms before the animation starts
  • animation-delay: 0s, no delay (default)
  • animation-delay: -0.4s, start immediately but 400ms into the animation cycle
  • Stagger multiple elements by giving each a slightly larger delay

animation-delay stagger

Three dots bounce in sequence, each delayed 0.15s more than the previous.

animation-iteration-count

animation-iteration-count sets how many times the animation cycles. Use infinite for looping animations, or a number to play it a fixed number of times.

animation-iteration-count

Most looping animations (spinners, pulsing indicators) use infinite. Use a specific count for one-time entrance animations or attention effects.

  • animation-iteration-count: 1, plays once and stops (default)
  • animation-iteration-count: 3, plays three times then stops
  • animation-iteration-count: infinite, loops forever
  • animation-iteration-count: 1.5, plays one and a half cycles then stops

animation-iteration-count: 3

The shake animation plays exactly three times then stops.

animation-direction

animation-direction controls whether the animation plays forwards, backwards, or alternates between the two on each cycle.

animation-direction

alternate is very useful for continuous looping animations, the element smoothly reverses at the end of each cycle instead of jumping back to the start.

  • normal, plays from 0% to 100% each cycle (default)
  • reverse, plays from 100% to 0% each cycle
  • alternate, plays forward on odd cycles, backward on even cycles
  • alternate-reverse, plays backward on odd cycles, forward on even cycles
  • alternate avoids a sudden jump back to the start in infinite loops

animation-direction: alternate

The bar expands and contracts smoothly because alternate reverses the animation each cycle.

animation-fill-mode

animation-fill-mode controls what styles are applied to the element before the animation starts (during the delay) and after it finishes.

animation-fill-mode

forwards is the most commonly needed value, without it, the element snaps back to its original styles the moment the animation ends.

  • none, element reverts to its original styles before and after the animation (default)
  • forwards, element keeps the styles from the last keyframe (100%) after the animation ends
  • backwards, element applies the styles from the first keyframe (0%) during the delay period
  • both, combines forwards and backwards behaviours
  • Use forwards on entrance animations so the element stays in its final position

animation-fill-mode

Both boxes animate once. The first snaps back to the start; the second stays in its final position.

animation-play-state

animation-play-state pauses or resumes an animation. Setting it to paused freezes the animation at its current frame. Resuming it with running continues from where it left off.

animation-play-state

A common pattern is to pause an animation on :hover and resume it when the user moves away, or use JavaScript to toggle paused/running dynamically.

  • running, animation plays normally (default)
  • paused, animation is frozen at its current frame
  • Toggle via :hover to pause on hover and resume on mouse-out
  • Toggle via JavaScript by changing the animation-play-state style property

animation-play-state: paused

The spinner pauses when hovered and resumes when the mouse leaves.

Animation Shorthand

The animation shorthand combines all animation properties in one declaration. The order is: name duration timing-function delay iteration-count direction fill-mode play-state.

animation shorthand

Only name and duration are required. The rest default to: ease, 0s delay, 1 iteration, normal direction, none fill-mode, running.

  • animation: slide-in 0.5s, name and duration only
  • animation: spin 1s linear infinite, name, duration, timing, iteration
  • animation: fade-up 0.6s ease forwards, name, duration, timing, fill-mode
  • animation: bounce 0.4s ease 0.2s 3, name, duration, timing, delay, count
  • Separate multiple animations with commas: animation: spin 1s linear infinite, pulse 2s ease alternate

animation shorthand

A badge entrance animation written entirely in the shorthand.

Multi-step Animations

By adding percentage steps inside @keyframes, you can create animations with many distinct phases. Each percentage marks a point in the animation timeline where styles change.

Multi-step @keyframes

Use percentage steps to choreograph complex animations with pauses, direction changes, and multiple property changes at precise moments.

  • 0% is the start, 100% is the end, add any percentages in between
  • Multiple selectors can share a step: 0%, 100% { ... }
  • The browser smoothly interpolates between each step
  • animation-timing-function inside a step, controls the curve from that step to the next
  • Keep multi-step animations purposeful, too many steps create visual noise

Multi-step animation

Each bar grows and shrinks through multiple keyframe steps to create a loading indicator.

Multi-step colour animation

A traffic light cycles through red, amber, and green using three keyframe steps.

Knowledge Check

1. Which rule defines the keyframes of a CSS animation?

2. What does animation-iteration-count: infinite do?

3. What does animation-fill-mode: forwards do?

4. Which animation-direction value makes the animation alternate between forward and backward?

5. What does animation-play-state: paused do?

6. Inside @keyframes, which keyword represents the start of the animation?