Easing and Bézier Curves in CSS
What is easing
Easing is the curve that defines how an animation progresses over time. Two animations with the same
distance and the same duration can feel completely different, because one speeds up at the start and slows
down at the end, while the other moves at the same pace the whole way. In CSS, this curve goes in
transition-timing-function or animation-timing-function, and when you don't set
one, the browser uses ease by default. It's what separates motion that feels mechanical from
motion that feels natural.
To read an easing curve, picture a graph where the horizontal axis is time and the vertical axis is
progress. Where the curve rises fast, the element moves fast, and where it lies almost flat, it's slowing
down. That's why an ease-out curve starts steep and ends flat: the element leaves quickly and
arrives slowly.
cubic-bezier()
The keywords ease, ease-in, ease-out and ease-in-out
aren't magic: each one is a cubic Bézier curve with fixed values. With the
cubic-bezier(x1, y1, x2, y2) function you choose those values, which are the two control
points of a curve that always starts at (0, 0) and ends at (1, 1). The x is time and must
stay between 0 and 1. The y is progress and can go past those limits, and that's what makes
the element overshoot its destination and come back, the back (or overshoot) effect. With a
negative y the opposite happens, and the element pulls back a little before leaving.
| Keyword | Equivalent to | When to use it |
|---|---|---|
linear |
cubic-bezier(0, 0, 1, 1) |
continuous spins, like a loading spinner |
ease |
cubic-bezier(0.25, 0.1, 0.25, 1) |
the default, when no easing is set |
ease-in |
cubic-bezier(0.42, 0, 1, 1) |
elements leaving the screen |
ease-out |
cubic-bezier(0, 0, 0.58, 1) |
elements entering the screen |
ease-in-out |
cubic-bezier(0.42, 0, 0.58, 1) |
an element moving from one point to another |
linear() and spring animations in CSS
A cubic-bezier overshoots its destination at most once, while a spring goes, comes back and goes again
until it settles. For that, CSS got the linear() function, which takes a list of points and
connects each one to the next with a straight line. It sounds limited, but with enough points those lines
can draw any curve, including spring, bounce and elastic.
.spring {
/* rises to 1.2 at 60% of the time, comes back to 0.9 at 80% and ends at 1 */
transition-timing-function: linear(0, 1.2 60%, 0.9 80%, 1);
}
When a point has no percentage, CSS spreads the points at equal intervals across the duration. A convincing spring needs dozens of points, and nobody writes that by hand, so they're generated from the physics of the spring and pasted into the CSS. The more points, the smoother the curve. With too few, the straight lines show and the motion looks choppy.
steps() and stepped animations
Not every animation needs to be smooth. The steps() function splits the duration into equal
intervals and makes the value jump from one to the next, with nothing in between, like the second hand of
a clock. It's what you use in a sprite animation, where each frame of the image appears all at once.
The number is how many intervals there are. The second parameter is optional and says when the value
jumps: with jump-end (the default, also written end) it jumps at the end of each
interval, and with jump-start (or start) at the beginning. There's also
jump-none, which shows the start and end values as full steps, and jump-both,
which jumps both at the beginning and at the end.
/* second hand: 60 steps in 60 seconds */
.second-hand {
animation: spin 60s steps(60) infinite;
}
@keyframes spin {
to {
rotate: 1turn;
}
}
You can build the same step with linear(). When a point gets two percentages, it holds the
value between them, and the line to the next point becomes a jump. The code below does the same as
steps(4, jump-none).
.step {
/* holds 0 until 25%, 0.333 until 50%, 0.667 until 75% and ends at 1 */
animation-timing-function: linear(0 0% 25%, 0.333 25% 50%, 0.667 50% 75%, 1 75%);
}
How to use the easing in your CSS
Any of these values goes where the easing goes, in both transition and
animation, either in the shorthand property or in transition-timing-function and
animation-timing-function.
.card {
transition: translate 0.4s
cubic-bezier(0.34, 1.56, 0.64, 1);
}
.toast {
animation: enter 0.6s
linear(0, 0.365, 0.829, 1.043, 1.071, 1.035, 1.006, 0.995, 1);
}
@keyframes enter {
from {
opacity: 0;
translate: 0 1rem;
}
}
A detail that trips up a lot of people with animation: the easing applies to each interval
between two keyframes, not to the whole animation. With keyframes at 0%, 50% and 100%, the curve runs
twice, once in each half. If you want a single curve from start to end, use only from and
to.
Frequently asked questions
Which easing should I use for most interface animations?
For elements entering the screen, I would use an ease-out or a stronger version of it, like
cubic-bezier(0.22, 1, 0.36, 1). It starts fast, which feels like an instant response, and
slows down gently at the end. For elements leaving, ease-in, and for continuous spins,
linear.
Can I make a spring animation with CSS only?
Yes, with linear(). What CSS doesn't do is real physics, so the spring always ends together
with the duration, even if a real spring would still be bouncing. I'd say that with a
well-chosen duration, almost nobody notices the difference.
Does linear() work in every browser?
Yes. According to MDN, linear() has been available in all major browsers since December
2023.
What is the difference between ease-in, ease-out and ease-in-out?
ease-in starts slow and ends fast, so it suits elements leaving the screen.
ease-out does the opposite, starting fast and ending slow, and suits elements entering.
ease-in-out is slow at both ends, good for an element moving from one point to another on
the screen.
References and inspiration
This project didn't come out of nowhere. These are the easing tools I use and recommend the most, and they inspired it.
-
cubic-bezier.com, by Lea Verou. The original, and
forever the coolest one in CSS. It's where a lot of people, me included, learned to drag the handles of
a
cubic-bezier()and compare the motion with the keywords. -
Easings.net, the catalog of classic curves like
easeOutQuintandeaseInOutBack, each one with its graph, motion and code. It's where I go when I need to find the name of a curve. - Easing Wizard, by Matthias Martin. One of the coolest easing tools out there, with Bézier, spring, bounce, wiggle and overshoot editors and the CSS ready to copy.