The KIRUPA orange logo! A stylized orange made to look like a glass of orange juice! Tutorials Books Videos Forums

Change the theme! Search!
Rambo ftw!

Customize Theme


Color

Background


Done

Making Sense of Timing Function Curves

by kirupa   |   28 December 2016

In the Working with CSS Timing Functions tutorial, we took a birds-eye view of what timing functions are and how you can use them in CSS to bring your animations and transitions to life. What we've really done is just looked at the mechanical details - the TL;DR version if you will. What you saw there will take you very far, but one thing we kinda glossed over is examining what goes into making a timing function (and its curve) look and behave the way it does. In the following sections, we'll look deeper at timing functions, what exactly goes into defining timing function curves, the math behind them, and various other related topics. This is going to be a fun one, so if your chair has seatbelts, I strongly suggest you wear them :P

Onwards!

Kirupa's book on web animation

OMG! An Animation Book Written by Kirupa?!!

To kick your animations skills into the stratosphere, everything you need to be an animations expert is available in both paperback and digital editions.

BUY ON AMAZON

The Timing Function Curve...Again!

When we talk about timing functions, we are often not talking about them in terms of their CSS names (ease, ease-in, etc.) Instead, timing functions are represented visually using something known as a timing function curve. We got a brief overview of them earlier. The main thing to know about them is this: The timing function curve helps us determine how a particular timing function will impact how property values change. The timing function curve isn't a generic representation for all timing functions, and each timing function has a very specific timing function curve associated with it. Knowing how to read them is an important part of being proficient with animations.

The Example

To help us make sense of timing curves, we are going to need a simple example. Our example is the following: we have an element whose opacity property value changes from 1 to 0 over a period of 2 seconds. To keep things simple, let's say that this change happens linearly.

A chart of this example where we plot the opacity value and duration would look as follows:

the opacity go down the hole

From looking at this chart, it is pretty easy to figure out what the value of our opacity property would be at any given point during the 2 second animation. At the 1 second mark, your opacity property would have a value of .5. At the 1.5 second mark, your opacity property would be .25, and so on.

Visualizing Timing Functions, Part I

Here is where things get interesting. Timing functions define the rate at which your property changes. What a property value is at any given time isn't nearly as important as how that property changed from its initial value to the final value over the lifetime of the animation. Our earlier chart where we plotted the opacity over a period of time isn't directly relevant to understanding timing function. To draw a chart through the eyes of a timing function, we are going to generalize things a bit and switch over to using percentages.

Instead of plotting the property value over a period of time, we are going to plot a ratio of both of them instead. Let's plot the percentage of how much progress the property has made to reach its final value compared to how much of the animation has been completed. Our earlier chart transformed to take into account these new expectations will look as follows:

percentage

While our graph looks different, the details that you had before is still represented here. You just have to dig a little bit deeper. In our example, the opacity property goes from starting at 1 to ending at 0. At the beginning with 0% of your animation having been completed, your opacity property is 0% of the way there to reaching its final value of 0:

at the beginning

That is why our blue line starts of at 0% for your property progression.

When your animation completes, your opacity property is at 0...aka the final value. Another way of saying that is that it reached 100% of where it needed to go, and it did that right at the end with 100% of your animation having been completed:

in the end, it doesn't even matter!

As you can see, our blue line ends at 100% for both completion as well as property progression. Because the change is linear, what you get is a straight line from the (0%, 0%) point at the bottom-left to the (100%, 100%) point at the top-right.

With this alternate representation for looking at your animation, the thing to note is that it no longer matters what the property value you care about actually is at the beginning or the end. The value could be something between 0 and 1 for opacity; something between #FFFFF and #00000 for a color; something positive and negative; and a whole lot more. It also no longer matters what the duration is. Your animation being .2 seconds long or 600 seconds long are no longer important. At this point, we've pretty much generalized all the pesky details away into the simple ratio between progress and completion. All that matters is what percentage of the final property value has been reached at any given point during the animation's lifetime.

Visualizing Timing Functions, Part II

This is far less dramatic than what this section heading may imply. The percentage-based graphs you saw in the previous section actually contain the timing function. I just didn't highlight it because the timing wasn't right:

the easing function

The blue line we've seen a few times already is the mythical timing function curve that represents the timing function. Now that you know this, let's try to understand this curve more.

Linear Cases

For a linear ease, as you have seen so far, the end result is a straight line. Your animation's completion and how far the property has progressed move hand-in-hand:

more progress

To highlight this, the arbitrarily chosen 30% mark represents both how far the property has progressed as well as how much of the animation has run to completion. Mapping this to what you will see on your screen, because the property is changing from 1 to 0 over 2 seconds, 30% represents an opacity value of .7 and an elapsed time of .6 seconds. This is just some simple multiplication.

For the most part, though, you will never actually need to do any simple multiplication to translate from this percentage based world to the actual property values. All you really need to know from looking at the timing function curve is how it will affect your animation. With a straight line like this, it is very clear how your final animation will be affected.

The Awesome Non-Linear Cases

Of course, not everything is as simple as what you have with a linear timing function. For the more realistic non-linear cases, how far your property has progressed will diverge from how much of your animation has actually been completed:

non-linear ease

For example, let's take a look at the 75% completion mark and see where things stand:

a look at the non-linear cases

Eyeballing things from this graph, your animation completing 75% of its life doesn't mean that the property has reached 75% of its final value. The value is more like 45% percent instead. From looking at the timing function curve, notice that your property changes don't catch up to your animation's completion percentage until the very end. What this means that your animation starts off pretty slow and then speeds up only much later. A different timing function may do something different, and you'll get to see a lot of these different timing functions shortly.

What You Can and Can't Do

We are almost done with the theoretical book learning. The last thing we are going to look at before getting even more serious is a boring overview of what you can and can't do using timing functions in CSS.

You Always Start at 0% and End at 100%

The most important limitation you should know about is that your property progression will always start at 0% in the beginning and end at 100% upon animation completion. It doesn't matter what your timing function does in the middle. The beginning and end are clearly defined and can't be changed:

starting and ending points are the same

What does this mean? This means your timing function can never get your animated properties to start off at anything but their initial values. Likewise, at the end of the animation, your timing function will never get your animated properties to stop at anything but the final value. Between the beginning and the end, the timing function may do all sorts of crazy things that affect the animated properties in similarly crazy ways. It is just that, at the beginning and the end, order is maintained.

There Is No Box

Speaking of crazy things that happen outside of the beginning and the end, your property values can change beyond 100% and below 0%:

going beyond 100

Being able to go beyond the range prescribed by your property's initial value and final value is a very important detail that can help make your animations more realistic! One of the 12 Basic Principles of Animation is called Follow through. Follow through refers to an animation technique where things don't stop animating suddenly. They exceed their final target slightly before snapping back into place. This useful technique is something that can only be done by going beyond the 0% and 100% range.

My Name is Curve...Cubic Bezier Curve!

So far, we've looked at timing functions in a very general, imprecise sense. As part of learning about them, such hand waving is acceptable. Now that we are getting close to better understanding them, we need to get a little bit more precise. Let's start with defining our timing function curve more formally.

Our timing function curve isn't simply called a timing function curve. That is simply its stage name. The timing function curves are more formally known as cubic bezier curves. While I won't go into great mathematical detail about cubic bezier curves, I will provide you with just enough information so that you can effectively use them to create awesome animations.

Let's get started by taking a look at the following timing func...err cubic bezier...curve:

simple easing function again

This curve doesn't look the way it does because it fell off the wagon like that. It looks this way because of various precisely placed points that mathematically influence its shape:

the cubic bezier curve in action

The thing to know is that a cubic bezier curve is made up of four points. I've labeled those four points, as seen in the above diagram, as P0, P1, P2, and P3. Each point is made up of two values that represent its horizontal and vertical position in our chart - two values we'll simply call x and y:

x and y values

I described the point values in terms of decimals as opposed to percentages because you'll rarely see percentages use to mark a cubic bezier point. From the above diagram, you can see how I got the values for both P1 and P2 pretty easily. I just translated the values from the completion and property progression axes into decimals. Notice that I didn't even bother labeling P0 and P3 because they are always going to be (0, 0) and (1, 1) respectively in our HTML world.

The point values are extremely important not just because they better explain our charts. They are important because it is these values that you specify in your CSS as part of using the cubic-bezier timing function. The first two arguments are made up of the x and y positions of point P1. The second two arguments are made up of the x and y positions of point P2:

definition time

Points P0 and P3 are ignored because they are always going to be the same. If you recall from earlier, your properties will always start at their initial value and always end at their final value. By not being able to specify them at all, you kinda ensure that is the case.

When you put those numbers in, your cubic-bezier timing function will look as follows:

.foo {
	transition: transform .5s cubic-bezier(.70, .35, .41, .78);
}

Now, for all practical purposes, you do not want to be randomly entering values into your cubic-bezier function and testing to see if the final result is what you like. That is just an awful use of time. What you want to do is visit the handful of online resources that simplify this task immensely such as Lea Verou's cubic-bezier generator.

Conclusion

The timing function curve is what everyone always talks about when dealing with timing functions. Knowing the exact details of how a timing function curve ends up looking the way it does or how it affects properties as they change isn't the most important thing in the world. Between our predefined easing functions and online generators for the cubic-bezier timing function, you have a very easy way of picking the right timing function with very little effort.

If that is the case, then what was the purpose of this tutorial? What did we gain by learning in detail about the timing function curve? The thing you gained is street-cred and, like I mentioned at the beginning, great stories to tell over dinner. In all seriousness, to truly master the craft of creating animations, you need to know everything you can about it. Fully understanding timing function curves falls under that everything bucket.

Just a final word before we wrap up. If you have a question and/or want to be part of a friendly, collaborative community of over 220k other developers like yourself, post on the forums for a quick response!

Kirupa's signature!

The KIRUPA Newsletter

Thought provoking content that lives at the intersection of design 🎨, development 🤖, and business 💰 - delivered weekly to over a bazillion subscribers!

SUBSCRIBE NOW

Creating engaging and entertaining content for designers and developers since 1998.

Follow:

Popular

Loose Ends