Animation is a great way to highlight interactive elements, and add interest and fun to your designs. In this module, find out how to add and control animation effects with CSS.
Sometimes you see little helpers on interfaces that provide some helpful information about the section they're in when you click them. These often have a pulsing animation to subtly let you know that the information is there and should be interacted with. This module shows you how to create those helpers, and other animations, using CSS.
You can use CSS to set an animation sequence with keyframes. These sequences can be basic, one-state animations or complex, time-based sequences.
What is a keyframe?
In most animation tools, keyframes are the mechanism you use to assign animation states to timestamps on a timeline.
For example, here's a timeline for the pulsing "helper" dot. The animation runs for 1 second and has 2 states.
There's a specific point where each of these animation states start and end. You map these out on the timeline with keyframes.
@keyframes
CSS @keyframes
are based on the same concept as animation keyframes.
Here's an example with two states:
@keyframes my-animation {
from {
transform: translateY(20px);
}
to {
transform: translateY(0px);
}
}
The first important part is the
custom identifier (custom-ident
),
the name of the keyframes rule. The identifier in this example is my-animation
.
The custom identifier works like a function name,
letting you reference the keyframes rule elsewhere in your CSS code.
Inside the keyframes rule, from
and to
are keywords that represent 0%
and
100%
, which are the start and end of the animation.
You could re-create the same rule like this:
@keyframes my-animation {
0% {
transform: translateY(20px);
}
100% {
transform: translateY(0px);
}
}
You can add as many positions as you like along the timeframe. In the pulsing helper example, there are two states that translate to two keyframes. This means you have two positions inside your keyframes rule to represent the changes for each of these keyframes.
@keyframes pulse {
0% {
opacity: 0;
}
50% {
transform: scale(1.4);
opacity: 0.4;
}
}
The animation
properties
To use your @keyframes
in a CSS rule, you can either define various animation
properties individually, or use the animation
shorthand property.
animation-duration
.my-element {
animation-duration: 10s;
}
The animation-duration
property defines how long the @keyframes
timeline should be as a time value.
It defaults to 0 seconds, which means the animation still runs, but it'll be too
quick for you to see. You can't use negative time values.
animation-timing-function
To help recreate natural motion in animation, you can use timing functions that
calculate the speed of an animation at each point. Calculated values are often
curved, making the animation run at variable speeds over the course of
animation-duration
, and making the element appear to bounce if the browser
calculates a value beyond those defined in @keyframes
.
There are several keywords available as presets in CSS, which are used as the value for
animation-timing-function:
linear
, ease
, ease-in
, ease-out
, ease-in-out
.
.my-element {
animation-timing-function: ease-in-out;
}
Easing function values appear to curve because easing is calculated using a
Bézier curve, a type of function used to model velocity. Each of the timing
function keywords, such as ease
, references a predefined Bézier curve. In CSS,
you can define a Bézier curve directly using the cubic-bezier()
function,
which accepts four number values: x1
, y1
, x2
, y2
.
.my-element {
animation-timing-function: cubic-bezier(.42, 0, .58, 1);
}
These values plot each part of the curve along the X and Y axis.
Understanding Bézier curves is complicated. Visual tools, such as this generator by Lea Verou, are very helpful.
The steps
easing function
Sometimes you might want to take more granular control of your animation by
moving in intervals instead of along a curve. The steps()
easing function lets
you break the timeline into defined intervals of equal duration.
.my-element {
animation-timing-function: steps(10, end);
}
The first argument is the number steps. If there are the same number of keyframes as steps, each keyframe plays in sequence for the exact duration of its step, with no transition between states. If there are fewer keyframes than steps, the browser adds steps between keyframes depending on the second argument.
The second argument is the direction. If it's set to end
, which is the
default, the steps finish at the end of your timeline. If it's set to start
,
the first step of your animation completes as soon as it starts, which means it
ends one step earlier than end
.
animation-iteration-count
.my-element {
animation-iteration-count: 10;
}
The animation-iteration-count
property defines how many times the @keyframes
timeline should run during the
animation. By default, this is 1, which means that the animation stops when it
reaches the end of your timeline. This value can't be a negative number.
To make your animation loop, set the iteration count to infinite
. This is how
the pulsing animation from the start of this lesson works.
animation-direction
.my-element {
animation-direction: reverse;
}
You can set which direction the timeline runs over your keyframes with animation-direction, which takes the following values:
normal
: the default value, which is forward.reverse
: runs backward over your timeline.alternate
: for each animation iteration, the timeline alternates between running forward and running backward.alternate-reverse
: Likealternate
, but the animation starts with the timeline running backward.
animation-delay
.my-element {
animation-delay: 5s;
}
The animation-delay
property defines how long the browser waits before starting the animation.
Like the animation-duration
property, this takes a time value.
Unlike animation-duration
, you can define animation-delay
as a negative
value, which makes the animation start at the corresponding point in your
timeline. For example, if your animation is 10 seconds long and you set
animation-delay
to -5s
, the animation starts from halfway through your
timeline.
animation-play-state
.my-element:hover {
animation-play-state: paused;
}
The animation-play-state
property lets you play and pause the animation.
The default value is running
. If you set it to paused
, the animation pauses.
animation-fill-mode
The animation-fill-mode
property defines which values in your @keyframes
timeline persist before the
animation starts or after it ends. The default value is none
, which means that
when the animation is complete, the values in your timeline are discarded.
Other options include:
forwards
: The last keyframe persists, based on the animation direction.backwards
: The first keyframe persists, based on the animation direction.both
: Both the first and last keyframes persist.
The animation
shorthand
Instead of defining each property separately, you can define them in an
animation
shorthand, which lets you define the animation properties in the
following order:
animation-name
animation-duration
animation-timing-function
animation-delay
animation-iteration-count
animation-direction
animation-fill-mode
animation-play-state
.my-element {
animation: my-animation 10s ease-in-out 1s infinite forwards forwards running;
}
Considerations when working with animation
Users can set their operating system to prefer reduced motion when interacting with applications and websites. You can detect this preference using the prefers-reduced-motion media query:
@media (prefers-reduced-motion) {
.my-autoplaying-animation {
animation-play-state: paused;
}
}
This isn't necessarily a preference for no animation. It's a preference for less animation, especially less unexpected animation. You can learn more about this preference and overall performance in our animation guide.
Check your understanding
Test your knowledge of animations
Is the name or custom identifier of a @keyframes
animation case sensitive?
The keywords from
and to
are the same as:
0
and 1
0%
and 100%
.start
and end
.The animation-timing-function
is also commonly known as:
What is the minimum number of keyframes required inside a @keyframes
animation?