better animation easings

You’ve doubtless used CSS transition or animation a million times by now:

a {
  transition: color 100ms;
}

Or, if you’ve gotten really fancy, perhaps you’ve specified an easing curve:

a {
  transition: color 100ms ease-in-out;
}

But have you ever stopped to consider if it’s the right easing curve? After all, every animation has some curve; that’s just one way of representing the motion taking place. Although there’s no “right” or “wrong” easing curves for every situation, each scenario will strongly lend itself toward a particular animation type for the most responsive, fluid-feeling result.

what is an easing curve?

The “bible of animation,” The Animator’s Survival Kit, illustrates the concept of easing well (as would be expected from Richard Williams). This section is a cheap imitation of the lessons there. I can’t recommend buying it enough as it teaches the fundamentals to animation in all forms, including web.

Think about animating a ball from left to right across the screen. And just for visualization, we’ll break the animation down into 24 frames (or steps).

0
24

Now, before continuing further, where would you imagine the ball would be for all the in-between frames? Let’s start with the most “logical” approach of diving the space perfectly evenly:

0
12
24

If we animate that, we see a robotic-looking animation that changes direction instantly and without any loss to momentum:

0
12
24

If we took that motion and plotted it on an 𝑥/𝑦 graph, with 𝑥 representing time and 𝑦 representing distance, we’d get the following:

Straight as an arrow. Because we divided the space evenly, at 25% of the time, the ball has covered 25% of the distance. At 50% of the time, 50% distance has been travelled, and so on, up to 100%.

This 𝑥/𝑦 representation of the animation is an easing curve. This is the only instance an easing “curve” will lack the curvy bits, and this is why dividing time/space evenly is called a linear curve (i.e. straight curve). This is simply the easiest to understand; in the next example we’ll see the “curve” part of it.

Now let’s try and animate the ball where the ball starts from 0 velocity, and ramps all the way up to maximum velocity by the end it reaches the right side. That causes the frames to cluster closer together when moving slowly, and space farther apart when speeding up, like so:

0
12
24

That, animated, produces the following “bouncy” animation:

0
12
24

And when plotted on 𝑥/𝑦 produces a sharp curve that starts at zero acceleration, and keeps accelerating all the way through the animation, reaching maximum velocity on the final frame:

This type of accelerating curve is called an ease-in curve for obvious reasons: it is slowest at the beginning (the “in”) of the animation. If it did the opposite—started at maximum velocity and decelerated down to zero—that would be called an ease-out curve.

If you combined the two, and had an animation where it started and ended at slow velocity, and reached maximum velocity in the middle, that’s an ease-in-out curve. Compare the graphs of the three:

ease-in
ease-out
ease-in-out

All together, these compose the four major types of easing curves—linear, ease-in, ease-out, and ease-in-out. Most animations use one of these four curves.

Of course, we’ve only scratched the surface. The ease-* curves may be tweaked slightly to provide more nuance to the motion (example). And there are more advanced curves that don’t fit into one of these categories (such as springs). But you now understand the “bread and butter” of animation curves from these four types alone.

So with that out of the way, here’s how to apply those in practice.

1. light, color, brightness, and opacity

When animating any properties of light (color, brightness, opacity), you’ll always want to use the linear easing curve.

a {
  transition: color 100ms linear;
}

Out of any standard easing curve, a linear one will produce the most even blend of color (that’s how color is already optimized to work!). Compare a linear transition (top) to an ease-out transition (middle) to an ease-in transition (bottom):

While nonlinear curves may be desirable with motion, they produce uneven blending for colors. You can see how a linear transition (top), for the most part*, blends color A and color B evenly. But when using ease-out (middle), the midpoint gets shifted too far left, and ease-in (bottom) shifts the midpoint too far right. So in most cases, a linear curve is the best option. Sure, there may be a super-specific usecase where you want to apply an easing curve to a color transition. But that will only ever work with a very specific curve and a very specific color transition—change one, and you must change the other (it will never be generally-applicable).

*If you think linear transitions don’t transition smoothly, congratulations! 🎉 You’ve found a rabbit hole into color theory. Good luck; have fun. But for your own sanity, just pretend that linear transitions are the smoothest among “dumb” non-color-aware easing curves. And pretend linear curves are good enough for animating (which, IMHO, they are).

The example above shows transitioning between 2 saturated colors, but the exact same thing happens with brightness and opacity, too:

You’ll notice the same results—ease-out and ease-in are too light, or too dark, respectively. So for transitions of light (color / brightness / opacity) use a linear curve.

2. rotation

Rotation is another good general application for a linear curve (though there may be a few more exceptions here).

The chief offender I see is “stuttering spinners” (left) that are more common than they should be:

Default ease
Linear curve

As you can see, the right linear animation is less distracting and moves more consistently. The poor excuse for a spinner on the left, bumping along almost like a flat tire, is what you get with the brower-default ease curve. Inspecting the code you’ll find the fix is as simple as a single CSS property:

 .spinner--stutter {
+  animation-timing-function: linear;
 }

Note: transition-timing-function is the equivalent property for CSS transitions you may be looking for

Rotation is a bit more nuanced than light, so a linear curve isn’t an “always” rule here (a good example is Material Design’s progress indicator, which is a multi-layered animation unifying several curves, but if you look closely, a linear rotation underpins the whole thing). But I’d still recommend starting with a linear curve for rotation and changing it if it’s not quite right.

3. interaction

Interactive elements is a broad category of animations, consisting of everything clickable, hoverable, draggable, etc. But despite its generality, here are 3 common mistakes that, if avoided, will probably take care of most animation issues in your UI:

mistake 1: sluggish interactions

Humans think of an interaction as “instant” (i.e. not slow) if it happens within ~100ms (source). While animation speed is important, we’ll focus on the easing curve. Compare the two examples of hover, with one using ease-in and the other using ease-out. Which feels more “instant”?

Hover me
Hovered!
ease in
Hover me
Hovered!
ease out

It may be hard to believe, but the two animations above are identical other than the easing curve (inspect if you don’t believe me)! Both animations have the same duration, and neither have a delayed start. But you can see for yourself what a difference the curve makes in the interactive feel!

As a general rule, ease-out curves are better for interactions because they respond quicker. The user is able to notice the change more easily because most of the movement happens up-front (scroll back to the ease-out curve earlier in the article as proof).

And as it goes with any rule of thumb, this rule can be broken, sure, and there are dozens of scenarios where ease-in or ease-in-out make a better animation. But starting with an ease-out curve for interactions will feel “right” most of the time.

mistake 2: easing drag events

Drag events should track 1:1 with the user’s mouse or touch input. Once you start animating everything, it’s easy to fall into the trap adding easing curves for things that shouldn’t be animated at all. Dragging is the chief offender.

Compare a draggable control with easing (above) vs. no easing (below):

Animating everything isn’t always “delightful,” especially when they stand in the way of more direct feedback. So reserve easings for the interactions that truly benefit from them.

3. not matching real-world motion

Using ease-out as a default easing will be best most of the time, but when is it not? If a component acts as a metaphor for a real-world item, that should cascade to animations, too.

A switch is a common example of this. Think about any light switch or device switch you’ve ever pressed. Of the two, which feels like it “clicks” like a switch would?

smooth ease-out curve
spring-loaded ease-in curve

The right behaves more like the real-world switch it represents—there’s a bit of resistance up front as you overcome the resistance of the internal spring, then the potential energy releases and the switch snaps into its final resting position. You can almost “hear” the 2nd switch click into place! Once again, the duration of both switches are identical and the easing curve is responsible for the noticeable difference in feel.

However, by adding resistance up-front (ease-in), we’re also fighting against one of our earlier principles—showing more movement up front so the interaction doesn’t feel “laggy” or delayed. So we’ll toy with the precise easing curve as well as timing to get that balance right between real-world metaphor vs responsive UI.

no resistance
(linear)
some resistance
(sharp ease-in)
too much resistance?
(very sharp ease-in)

We’re now in the realm of subjective opinion where you, the implementer, have freedom to explore the nuances of movement and do what you feel is right. But no matter what you decide, you’re now animating things in a much more thoughtful (and realism-inspired) way.

general recommendation

Again, since interactions are complex and very situational, it’s hard to develop blanket rules. But hopefully these 3 mistakes get you thinking about how to reason through what works and what doesn’t in animating each scenario. But when in doubt, defaulting to ease-out will be right for most interactions. Change it if needed (especially if a real-world parallel behaves differently), and never forget that no easing is always an option (as in the dragging example).

summary

Now that you’ve been made aware of the quick wins, you can apply the following today for a much-improved user experience:

  • light: use linear easing
  • rotation: start with linear easing by default, but adjust to taste
  • interactions: start with ease-out by default, but adjust to taste, and also consider no easing as an option

But there are many more challenges beyond this! And there are more niche, contextual situations to encounter where easing may be more complex. For example, think back to the dragging example above. What if the handle needed to reset back to center after dragging (like a joystick)? You’d need to remove the easing curve while dragging, but re-apply it as it “slid” back to center position. Keep an eye out for multi-layered easings where one component may require different animations for different states.

In respect of that, some more nuanced, universal approaches to animation easings would be:

  • easings help the human brain notice a change (e.g. an object animating across a screen will be better perceived than “teleporting” in one frame). use them to improve recognition of an action
  • more movement & change up-front also help with this recognition (ease-out)
  • make animations mimic the real world (e.g. all objects have momentum while moving and accelerate/decelerate appropriately; switches “flick” on-and-off and don’t smoothly glide, etc.)

Play around with your newfound skills and you’ll be making more sophisticated animations in no time. However, you’re also now cursed with noticing bad animation everywhere you look, so good luck with that, too.

Hayao Mizazaki: “Anime was a mistake. It’s nothing but trash”

more reading / resources