DevPath · Learn to code ESPTEN

Transitions, transforms and animations

@keyframes, animation and prefers-reduced-motion

When a transition is not enough

A transition animates from a state A to a state B, and it needs a trigger (a :hover, a click...). But what about a spinner that turns on its own, a heart that beats or an element that blinks? For animations with several steps, that repeat or that start on their own, we use @keyframes together with the animation property.

Defining the frames

@keyframes heartbeat {
  0%   { transform: scale(1); }
  50%  { transform: scale(1.2); }
  100% { transform: scale(1); }
}

You can also use the keywords from (= 0%) and to (= 100%):

@keyframes appear {
  from { opacity: 0; }
  to   { opacity: 1; }
}

Applying the animation

.heart {
  animation: heartbeat 1s ease-in-out infinite;
}

The shorthand form of animation accepts, among others:

Accessibility: prefers-reduced-motion

Not everyone enjoys motion: for some people, too much animation triggers real dizziness or discomfort. Respect their system setting with the media query prefers-reduced-motion:

@media (prefers-reduced-motion: reduce) {
  .heart {
    animation: none;   /* disable the motion */
  }
}

Good practice: animate by default, but override the animations when the user asks for less motion. It is an accessibility requirement, not an extra.

Examples

Animation name referenced by @keyframes

const animation = "heartbeat 1s ease-in-out infinite";
console.log(animation);
Put this into practice

DevPath is a hands-on course: you read the theory here; in the app you put it into practice with exercises that really run, offline.

Start free in the app →
← transition: animate state changesView the module →