Have you ever noticed how smooth and delightful animations look on a well-made, professional project? I am reminded of the In Pieces website where animations are used not just for decoration, but they also convey the message about the endangered species in an impactful way. Not only is the animation design and style beautiful, but they also flow nicely and harmoniously. It is precisely that flow in combination with the design and presentation which makes the animation look stunning and natural. That is the power of easing functions, which are also called timing functions.
When writing transition and animation properties in CSS, we usually go for the pre-defined easing functions like ease-out
because it’s simple, they look alright and they work well for most cases. However, having a dozen or more elements on a page with an animation that features the same duration and easing function values may make the UI a bit bland and monotone. Humans respond better to natural motion, so making the animation and transition more varied and natural will result in a better user experience.
If we go back to the In Pieces example and inspect the stylesheet, we can notice that various custom cubic-bezier
easing functions are used in combination with the pre-defined linear
and ease-in
timing functions to achieve that beautiful animation flow. Animations wouldn’t look as good if only pre-defined easing functions were used instead of custom easing functions. Following video showcases In Pieces website with all easing functions set to ease-out
. Even though there is nothing wrong with the animations, notice how they are not as stunning nor exciting as the original animations.
In this article, we’re going to take a deep dive into CSS easing functions, types of easing functions, and how to create custom easing functions using Cubic Bézier curves.
Under The Hood
In order to get a better understanding of easing functions, we need to take a step back and take a look at the animation basics in CSS.
Animation is defined by keyframes which determine how an element should look and be positioned at certain points. CSS Transitions use two keyframes (starting and ending value), while CSS animations allow more precise control with the @keyframes
rule.
Animation duration determines the amount of time for the animation to go from the first keyframe to the last. The following graph shows the connection between the animation keyframes and duration.
There are many ways in which animation can progress between two keyframes. For example, animation can have a constant speed or it can move quickly at the start and slow down near the end, or move slowly at the start and then speed up until it reaches the end, etc. This rate, or speed is defined with the easing functions (timing functions). If we take a look at the previous graph, the easing function is represented by the shape of the line connecting the two points. We’ve used the linear function (straight line) for the previous example, but we can also use a curve to connect the keyframes.
As you can see, there are lots of possible options and variations for animation easing functions and we’ll take a look at them next.
Types Of Easing Functions
There are three main types of easing functions that can be used in CSS:
- Linear functions (
linear
), - Cubic Bézier functions (includes
ease
,ease-in
,ease-out
andease-in-out
), - Staircase functions (
steps
).
Linear Functions
We’ve covered linear functions in one of the previous examples, so let’s do a quick recap. With the linear timing function, the animation is going through the keyframes at a constant speed. As you might already know, the linear timing function can be easily set in CSS by using the linear
keyword.
Cubic Bézier Functions
Although linear timing functions have their use-cases, they can make the animations look bland and unnatural if used incorrectly or used too often. As we’ve seen from the In Pieces example, users respond better to natural motion, i.e. non-linear timing functions which can accelerate and decelerate.
Bézier curves are commonly used in vector graphics, animations and robotics to easily create smooth curves and trajectories. In CSS we are using Bézier curves defined by four points, which are known as Cubic Bézier curves.
Commonly-used pre-defined easing functions like ease
, ease-in
, ease-out
, and ease-in-out
belong to the Cubic Bézier functions. They can be used as a quick way to set a non-linear easing function. Even a linear function can be defined using a cubic-bezier
function.
Easing Function | cubic-bezier Value |
Starting Speed | Middle Speed | Ending Speed |
---|---|---|---|---|
linear |
cubic-bezier(0.0, 0.0, 1.0, 1.0) |
constant | constant | constant |
ease |
cubic-bezier(0.25, 0.1, 0.25, 1.0) |
fast acceleration | fast acceleration | slow acceleration |
ease-in |
cubic-bezier(0.42, 0, 1.0, 1.0) |
slow acceleration | fast acceleration | full speed |
ease-out |
cubic-bezier(0, 0, 0.58, 1.0) |
full speed | slow acceleration | slow acceleration |
ease-in-out |
cubic-bezier(0.42, 0, 0.58, 1.0) |
slow acceleration | full speed | fast acceleration |
Even though pre-defined values work well for many cases, knowing how to create custom Cubic Bézier functions gives you even more control over the look and feel of the animation which can make the animation look even more impressive and impactful.
In the following example, I’ve edited the animations for In Pieces example to use a different Cubic Bézier function with different values. You can see how vastly different the animation looks and feels with this easing function.
cubic-bezier(0, 1.2, 1, 0.2)
Let’s take a look at the cubic-bezier
function which is used to define Cubic Bézier curves in CSS. Cubic Bézier function is defined by four points (x and y coordinate pairs), but we only define 2 points in cubic-bezier
function. Why is that?
This is because the first (P0) and last points (P3) are fixed to the start (initial animation state) and the end (final animation state) of the curve, as the animation needs to end on a specified keyframe and within the specified duration. With the two remaining points (P1 and P2), we can fine-tune the curve and easing of the function, resulting with non-linear animation speed.
cubic-bezier(x1, y1, x2, y2)
X coordinates (x1
and x2
) represent time ratio and are limited to values between 0 and 1 (the animation cannot begin sooner or last longer than specified), while Y coordinates (y1
and y2
) represent the animation output and their values, which are usually set somewhere between 0 and 1 but are not limited to that range. We can use the y1
and y2
values that are outside the 0 and 1 range to create bouncing effects.
If the animation consists of several keyframes, defined in CSS @keyframes
property, the easing function will be applied to each curve between the two points. If we are applying ease-out
function to an animation with 3 keyframes, the animation will accelerate at the start of the first keyframe, and decelerate near the second keyframe and the same motion will be repeated for the next pair of keyframes (second keyframe and the last keyframe).
Notice how the easing function is repeated between each keyframe pair — first and second keyframes (first pair), and second keyframe and last keyframe (second pair). The animation duration is the same for both the previous and the following examples.
Creating these functions can be a complex task, so you probably won’t be adjusting the coordinates by guessing the cubic-bezier
parameters. You’ll have to use a tool to help you nail those magic numbers in order to create a timing function that perfectly fits your animation. Luckily, there are numerous browser and online tools to help us out. We’ll talk about them in one of the following sections in this article.
Staircase Functions
Staircase functions enable animation to jump between the specific number of frames in a non-continuous way. You can think of it as a “ticking” animation.
For example, if we take a look at one of the previous examples where a box moves from 0px to 500px and we limit the animations to 5 steps, the animation will jump between the following 5 keyframes — 0px, 100px, 200px, 300px and 400px positions.
We can easily achieve this with steps
function in CSS.
steps(number_of_frames)
steps(5)
This function has an additional option for controlling which keyframes are included. As you have seen from the previous example, the animation of a box moving from 0px to 500px with 5 steps will end in a 400px position. If we want the animation to start from 100px and end in a 500px position, we can use the jump term option as a second argument. Jump term affects how the keyframes will be selected from the animation timeline.
steps(number_of_frames, jump_term)
steps(5, jump-start)
Following jump term options can be used in CSS steps
function:
jump-start
Animation jumps right from the starting point and the starting point is not visible t. From our example example, keyframes will be 100px, 200px, 300px, 400px, 500px.jump-end
Last jump happens when animation ends and is not visible. From our example example, keyframes will be 0px, 100px, 200px, 300px, 400px.jump-both
Both the first and last jump will happen as animation starts and ends respectively, so they won’t be visible. All 5 jumps will happen between staring and ending points. From our example, those keyframes will be 80px, 165px, 250px, 335px, 420px.jump-none
Both first and last jump will be visible. From our example, those keyframes will be 0px, 125px, 250px, 375px, 500px.
The following example showcases how various jump terms affect the animation behavior. Various jump terms are applied to the 5-step animation with the same duration.
Debugging Animations And Useful Tools
As we’ve seen from the Cubic Bézier example, we need some kind of tool that will help us fine-tune the Cubic Bézier curve parameters so we can achieve the look and feel of the animation that we want.
In this section, we’ll take a look at the browser tools, websites, and CSS styles that should help us do just that.
Browser Tools
Browser developer tools provide useful easing function editing features out of the box. Please note that only Cubic Bézier functions are available for editing. These tools offer a quick and simple animation preview so that the developer can get instant feedback and fine-tune the easing function.
Chrome, Safari and Firefox also offer a dedicated Animations tab in developer tools that offers a more detailed overview, including animation properties, duration, timeline, keyframes, delay, etc.
Useful Tools And Websites
There are plenty of useful online resources and easing presets that can give much more variety to easing functions.
More popular online resources include Easing Functions Cheat Sheet by Andrey Sitnik and Ivan Solovev and CSS Easing Animation Tool by Matthew Lein. These tools offer a wide range of presets that you can use as a foundation for your easing function and then fine-tune the curve to fit your animation timeline.
Animations & Accessibility
When working with easing functions and animations in general, it’s important to address accessibility requirements. Some people prefer browsing the web with reduced motion, so we should provide a proper fallback. This can be easily done with widely-supported prefers-reduced-motion media query. This media query allows us to either remove the animation or assign a different animation based on user preference.
.animated-element { animation: /* Regular animation */;
} @media (prefers-reduced-motion) { .animated-element { /* Accessible animation with reduced motion */ }
}
I’ve modified an analog clock example by Alvaro Montoro to include alternative animation for users with prefers-reduced-motion
flag set.
On a default animation, the seconds hand of the clock is constantly moving which may cause difficulties for some users. We can easily make the animation much more accessible by changing the animation timing function to steps
. In the following example, users with prefers-reduced-motion
flag set will be displayed an animation where seconds arm ticks every five seconds.
@media (prefers-reduced-motion) { .arm.second { animation-timing-function: steps(12); }
}
Conclusion
Easing functions, or timing functions, change the animation’s look and feel by affecting the animation rate (speed). Easing functions enable us to create animations that resemble natural motion which can result in improved, more delightful UX and having a better impression on the users. We’ve seen how we can use pre-defined values like linear
, ease-out
, ease
, etc. to quickly add a timing function and how to create custom easing functions with cubic-bezier
function for more impressive and impactful animations. We’ve also covered staircase functions that can be used to create “ticking” animation and are rarely used. When creating animations, it’s important to keep accessibility in mind and provide an alternative, less distracting animations with less motion to users with prefers-reduced-motion
flag set.
There are plenty of browser and online tools that can simplify and streamline creating custom easing functions, so creating animations with a beautiful flow is easier than ever. If you haven’t done so already, I would recommend experimenting with various easing functions and creating your own easing function library.
References
<easing-function>
, MDN Web Docs- “Work With Animations,” MDN Web Docs
- “Web Animations In Safari 13.1,” Antoine Quint, WebKit
- “The Basics Of Easing,” Paul Lewis, Web Fundamentals, Google Developers
- “Inspect Animations,” Kayce Basques, Chrome DevTools, Chrome Developers
(vf, yk, il)