Cubic Bezier Curves in CSS3

In the last post, we looked at the basics of CSS transitions, including how to use easing to control how your animation flows. In this post, I want to look deeper at a very powerful easing feature; cubic bezier curves.

In short, they let you define exactly what path your animation will take, and thanks to some awesome community tools, they are extremely easy to use (No maths required at all). This gives you total flexibility with your transitions.

One of the best tools is the free Cubic-Bezier.com by Lea Verou. It lets you make new curves and see them in action just by dragging the handles. We’ll use it for all of the demos in this post, and it’s well worth a bookmark!

The syntax is simple too. Let’s look at an example. This simple code can be used to animate an element left or right:

1
2
3
4
5
6
7
8
9
10
11
12
a.slide {
  position: relative;
  transition: left 1.5s linear;
}
 
a.slide-left {
  left: 0;
}
 
a.slide-right {
  left: 580px;
}

The linear part is actually a shortcut though. What it really says is that you want the animation to follow a particular path on a graph, which we’ll look at more in a second.

For now, you could rewrite that line to use the cubic-bezier function and get the exact same animation:

1
transition: left 1.5s cubic-bezier(0, 0, 1, 1);

That one line can now be used in any transition, and to tweak the animation, all you need to do is change those 4 bracketed values.

What Is This Graph?

Let’s take a look at the linear graph, and see what it means.

Linear Animation

The x-axis represents the time of your animation. The y-axis represents how far it is between its starting state, and its ending state.

The x-axis is easier to understand; the far left is the very start of your animation. As you go right, time progresses towards the ending time.

To grasp the y-axis, think of the slide-to-the-right animation. At the very bottom of the y-axis, our button hasn’t moved, it’s still on the left of the screen. Half way up the y-axis though, it’s now half way between the left and right side of the screen, and at the top of the axis, it is now at the far right.

The Ease Graph

Ease is the default easing style used, and it has the following graph:

Ease Animation

I’ve drawn a red line representing a linear animation on the graph, to help highlight the difference. Reading from left-to-right (start to finish) on the graph, you can see that:

  • The ease animation dips under the linear line slightly at the beginning, so it starts off a little slower.
  • It then rises more steeply to be much well above the linear line, so the middle of the animation is quite fast.
  • Finally, the line flattens out again at the top, so the animation slows down gracefully towards the end.

The values we pass to cubic-bezier are the co-ordinates of the pink and green circles on each graph (In the first, the green circle is hidden under the white corner at the top right of the graph).

The specific points used for ease are:

Ease Coordinates

Therefore, the code to draw this graph is:

1
transition: left 1.5s cubic-bezier(.25, .1, .25, 1);

Custom Animations

Now that you understand what these graphs tell you, let’s make some custom animations.

Say you liked the ease animation, but you wanted to make it a little slower again at the start. You would take the first (pink) point, and drag it to the right. You are saying that rather than getting to this stage after 25% of the animation, I now want it to take 40% of the animation’s total time.

Slower Ease

1
transition: left 1.5s cubic-bezier(.4, .1, .25, 1);

Now let’s go more extreme. Let’s say you wanted the middle of the animation to be really, really fast, but the start and end to be more gradual.

Sharp Middle

1
transition: left 1.5s cubic-bezier(1, 0, 0, 1);

Or of course, you could make the start go faster and the end go slower.

Fast Start Animation

1
transition: left 1.5s cubic-bezier(0.1, 0.25, 0.25, 1);

How about a really slow start with a very fast end?

Fast Ending Animation

1
transition: left 1.5s cubic-bezier(1, 0, 1, 1);

That should be plenty of regular examples for now. There are endless combinations you can set up, so let’s move on to another nifty trick; going beyond the ends of the graph.

Going Past The Start and End

All of our animations so far have started at 0 on the y-axis, and ended at 1. You don’t have to stick to these limits though. It is entirely possible to have your animation go past its supposed end point, and then circle back to it.

In this example, our button start off slow, build up speed, slide right past its goal, and then reverse back into place.

Animate Past the End

1
transition: left 1.5s cubic-bezier(0.4, 0.1, 0.55, 1.3);

These sorts of animations can feel much more natural. As an example, think of scrolling webpages on your phone/tablet. When you flick down to the very bottom or the very top, the page goes right past the top and bottom and then glides back into place.

If you really wanted, you can also do the opposite and have your animation go backwards in the beginning.

Animate Backwards

1
transition: left 1.5s cubic-bezier(0.4, -0.45, 1, 0.9);

There are 2 natural limitations to these techniques though:

  • The time can’t be adjusted in this way. It will always be whatever length you specified.
  • For some CSS properties, going above/below the y-axis boundaries will have no effect, e.g. opacity. The element can’t be any less visible than invisible…

The best thing to do is to experiment. The syntax is incredibly simple. Set up your animation using the cubic-bezier for the default ease function. Once it’s working, tweak the values to see what looks best.

Enjoy this post? You should follow me on Twitter!