Curso Animações Web

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.

The keywords and their equivalent cubic-bezier()
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 easeOutQuint and easeInOutBack, 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.