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:
- name: that of the
@keyframes(heartbeat). - duration:
1s,500ms... - timing function:
ease-in-out,linear... - iterations: a number or
infinite. - direction:
normal,alternate(goes and comes back)...
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);