# Realistic animations with CSS easing functions: Bouncing balls, pendulums and tossing books

CSS gives us a list of built-in easing functions for animations, but did you know that they mimic the movement of real world objects - like a bouncing ball or a pendulum?

Under the hood, the timing-functions like `ease-in`

or `ease-in-out`

are just cubic-bezier curves with predefined parameters, but those parameters aren't random at all.

Follow me on a journey through the CSS timing functions and discover how they relate to objects moving in gravity - the good news is, they do all the physics stuff for you, so you won't have to!

*Note: This article assumes that you're already familiar with cubic-bezier timing-functions in CSS animations. If you'd like to learn the fundamentals, or need a little refresher, I've written a detailed introduction to cubic-bezier timing-functions in a previous article -> Mastering cubic-bezier timing-functions: An easy guide*

## Bouncing ball

### Bouncing ball with keyframes

Let's jump right in with a full dose of physics 🤟

I know I just said we won't need physics, but it's a simple calculation, so please bear with me - going through this process once will help us understand later where the parameters of the built-in CSS timing-functions are coming from.

If an object falls in a gravitational field, the distance that it has fallen is proportional to the time squared:

`distance ~ t²`

Using that, we can write a bouncing-ball keyframe-animation like this:

```
@keyframes bounce-keyframes {
0%: {top: 0%}
10%: {top: 1%}
20%: {top: 4%}
30%: {top: 9%}
40%: {top: 16%}
50%: {top: 25%}
60%: {top: 36%}
70%: {top: 49%}
80%: {top: 64%}
90%: {top: 81%}
100%: {top: 100%}
}
.ball {
animation: bounce-keyframes 0.6s linear infinite alternate;
}
```

Result - a perfect bouncing ball:

But do we really need to write out that whole set of keyframes for a simple bouncing ball? Of course not 😏

### Discover the power of timing-functions

The above approach asks **"How far has an object fallen after x% of the total time?"**. Then we calculate those distances for 10 time values, so we get 10 pairs of time/distance values. With those, the animation already runs fairly smooth, and it would be even smoother if we added more value pairs.

However, one could also ask **"How much time has passed after the object has fallen y% of the total height?"**. Instead of manually calculating a number of time/distance value pairs, we only need one timing-function, and get a practically infinite number of keyframes. Animation smoothness:👉 💯

### Bouncing ball with `ease-in`

and `ease-out`

Most of you probably know already that we could've achieved the same movement using the built-in CSS cubic-bezier functions `ease-in`

or `ease-out`

.

**One keyframe, one timing function, no math:**

```
@keyframes bounce-fall {
0%: {top: 0%}
100%: {top: 100%}
}
@keyframes bounce-rise {
0%: {top: 100%}
100%: {top: 0%}
}
.ball-left {
animation: bounce-fall 0.6s ease-in infinite alternate;
}
.ball-right {
animation: bounce-rise 0.6s ease-out infinite alternate;
}
```

These two timing-functions are symmetrical. We can either animate the falling part with `ease-in`

, or the rising part with `ease-out`

. Setting the `animation-direction`

property to `alternate`

provides the second half of the movement.

The point to take away from this is that the CSS timing functions help us create animations that look real and natural. `ease-in`

and `ease-out`

describe a quadratic relation of time and property. If that property is something like a vertical distance/height, the timing-function describes how an object falls in a gravitational field.

## Combining `ease-in`

and `linear`

Making the ball bounce over to the right can be done by superposition of the falling animation with a linear movement:

```
@keyframes bounce-ease-in {
0%: {top: 0%}
100%: {top: 100%}
}
@keyframes move-right {
0%: {left: 0%}
100%: {left: 100%}
}
.ball {
animation:
bounce-ease-in 0.6s ease-in infinite alternate,
move-right 3s linear infinite;
}
```

Another use case - ball rolling down a ramp:

## Pendulum

So far, we've covered `linear`

, `ease-in`

and `ease-out`

. What about `ease-in-out`

?

The image below shows all three curves in one plot:

- start point handle of
`ease-in-out`

= start point handle of`ease-in`

- end point handle of
`ease-in-out`

= end point handle of`ease-out`

`ease-in-out`

is a combination of both - and results in a symmetrical **(sine)** curve (see a demo here on codepen).

So this timing-function could for example describe the movement of a pendulum, when the animated property is the angle of rotation:

## The mysterious ease function

This timing-function puzzles me a little. As seen above, the other easing functions have simple real-world equivalents:

- the quadradic-bezier-curves for dropping an object or throwing it upwards (
`ease-in`

and`ease-out`

) - the cubic-bezier-curve for a periodic movement governed by a sine-function (
`ease-in-out`

)

I couldn't find any hints where the parameters of the `ease`

function are coming from, though. Looking at the curve and the resulting animation:

- something starts with an initial speed
`> 0`

- it accelerates for a short while (about 25% of the total animation time)
- for the remaining 75% of time, it gradually slows down until its speed is
`0`

Trying to come up with a real-world example for this function: Tossing a book on a table. While my hand still holds the book, it accelerates. After throwing it, it slides over the table and quickly slows down due to friction.

However, this seems a little random, doesn't it? If you have a better explanation concerning the parameters of the `ease`

timing-function, please leave a comment below! 👇

## Realism in animations

I'd like to go back to the example above, where we calculated the keyframes for a bouncing ball. The formula we applied was:

`distance ~ time²`

This formula is universally true for every bouncing ball on every planet. Can we modify it so it describes a bouncing ball *on earth*?

Prepare for a weird exercise 🙃

### Dropping a ball on earth

To make the above calculation specifically with earth's gravity, we'll have to add a factor to account for the gravitational acceleration on earth (`g = 9.81 m/s²`

):

`distance = 0.5 · g · time²`

Let's say I'm animating an element that falls a distance of 300px. Assuming a monitor resolution of `100px/inch`

, my 300px would equal 3 inches (7,62 cm). Calculating the time (= `animation-duration`

):

`t = √(2 · distance / g) = 0.125 s`

Alright, here's the resulting animation. Does that look realistic? 😳

Yes, stuff really falls that fast! If you don't believe me, grab a rubber or pen and let it fall in front of your screen.

### Importance of scale/dimension

The reason why it looks unrealistic while it *is* realistic is that we're used to seeing things on a screen that are actually much bigger. If we give a scene some context by adding visual elements that define the dimensions to apply, they make sense again.

### Basketball

See the below animation of a basketball. The hoop is approximately 3 meters high, so the ball falls for 0.78s - and the animation looks perfectly realistic to our eyes:

### Pendulums

We can do the same "realistic" calculations with our pendulum to find out the exact time period to apply. We'll need a little bit of theory first, though:

It's a bit counter-intuitive, but for the time period of a pendulum, it doesn't matter how heavy the ball is. It's also irrelevant if we let it start swinging at a small or a large angle.

The only things that define the time period of a pendulum are the length of the string and the gravitational acceleration `g`

:

`T = 2 · π · √ (length/g)`

Assuming that we're staying on earth with our animations, the only question is - how long is that string?

Again, adding some visuals to indicate the dimensions to apply:

## Summary

- the CSS timing-functions
`ease-in`

and`ease-out`

describe how an object falls under the influence of gravity - the
`ease-in-out`

timing-function describes a periodical movement according to a sine-function (like a pendulum under gravity) - given fixed dimensions, the strength of the gravitational force can be modified by changing the
`animation-duration`

- animations look realistic if the dimensions and time values are chosen such that the resulting movement meets the (implicit) expectations of the viewer
- for completeness: a full list of all timing functions in MDN docs

### Thank you for reading!

I hope you enjoyed this little trip through the CSS timing-functions. Please leave any comments or feedback below, or @ me on Twitter - especially if you can shed some light on the mystery of the `ease`

function parameters! If you liked this post, I invite you to subsribe to my newsletter. Until next time 👋