ShareYourGroupShareYourGroupCSS Lab

CSS animations explained: keyframes, timing and reduced motion

CSS can move things without any JavaScript. This guide explains the pieces and the habits that keep animations smooth and respectful.

Transition or animation?

A transition changes a property from one value to another when something happens, such as a hover. An animation runs by itself through several steps called keyframes, can repeat, and does not need a trigger. Use a transition for state changes (transition: transform 0.2s ease) and an animation for loops, entrances and attention effects.

Keyframes

@keyframes bounce { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-30px); } } defines the steps. Percentages are points in time of one run. from and to are the same as 0% and 100%. Then an element uses it: animation: bounce 1.2s ease-in-out infinite;.

The shorthand in order

animation: name duration timing-function delay iteration-count direction fill-mode. Two numbers with units (times) appear: the first is the duration, the second the delay. The generator writes them in this order.

Timing functions

linear is constant speed. ease (the default) starts quickly and ends slowly. ease-in-out is slow at both ends. cubic-bezier(a, b, c, d) is any custom curve; values above 1 overshoot, which gives a springy feel. steps(n) jumps, useful for sprite sheets and typing effects.

Fill mode

By default an element goes back to its normal style after the animation ends. forwards keeps the last keyframe, backwards applies the first keyframe during the delay, and both does both. For entrance effects, both prevents a flash of the final state before the animation starts.

Keep it smooth

The browser can animate transform and opacity on the graphics card without recalculating the page layout. Animating width, height, top, left or margin forces layout work for every frame, which stutters on phones. Move things with translate, resize with scale.

Reduced motion

Some people get dizzy or distracted by motion, and they turn on "reduce motion" in their system. Respect it:

@media (prefers-reduced-motion: reduce) {
  .element { animation: none; }
}

Keep the content visible in that case (for example, an element that fades in must still show).

Good habits

Why does my animation run only once?

It ran, ended, and the browser does not restart it unless the animation name changes or the class is removed and added again.

How do I run something after the animation ends?

Listen for the animationend event in JavaScript.

This is an independent site. It is not connected with the W3C, MDN, Google, Apple, Mozilla or Microsoft. Browser and product names belong to their owners.