With the new CSS linear()
easing function on the horizon, the possibilities of what we can do to
create natural-feeling animations and transitions in the future are
greatly expanded. Jhey Tompkins looks at the current state of CSS easing
in this article and demonstrates what we can expect from linear()
, including handy tools to get your hands on it today.
To paraphrase a saying that has always stuck with me: “The best animation is that which goes unnoticed.” One of the most important concepts of motion design on the web is making motion “feel right.” At the same time, CSS has been fairly limited when it comes to creating animations and transitions that feel natural and are unobtrusive to the user experience.
Fortunately,
that’s changing. Today, let’s look at new easing capabilities arriving
in CSS. Specifically, I want to demonstrate the easing superpowers of linear()
— a new easing function that is currently defined in the CSS Easing
Level 2 specification in the Editor’s Draft. Together, we’ll explore its
ability to craft custom easing curves that lead to natural-feeling UI
movement.
The fact that linear()
is in the Editor’s
Draft status means we’re diving into something still taking shape and
could change by the time it reaches the Candidate Recommendation. As you
might imagine, that means linear()
has limited support at this moment in time. It is supported in Chrome and Firefox, however, so be sure to bear that in mind as we get into some demos.
Before we jump straight in, there are a couple of articles I recommend checking out. They’ve really influenced how I approach UI motion design as a whole:
- “Good to great UI animation tips,” Pablo Stanley
- “Disney’s Motion Principles in designing interface animations,” Ruthiran Babu
There are plenty of great resources for designing motion in UI, but those are two that I always keep within reach in my browser’s bookmarks, and they have certainly influenced this article.
The Current State Of Easing In CSS #
We define CSS easing with either the animation-timing-function
or transition-timing-function
properties, depending on whether we are working with an animation or transition respectively.
Duration is all about timing, and timing has a big impact on the movement’s naturalness.
“
But, until recently, CSS has limited us to the following easing functions:
linear
,steps
,ease
,ease-in
,ease-out
,ease-in-out
,cubic-bezier()
.
For a refresher, check out this demo that shows the effect of different timings on how this car travels down the track.
The cubic-bezier()
function has traditionally provided the most flexibility for creating easing with a little character. The site cubic-bezier.com is a great resource for creating bespoke easing functions. Otherwise, figuring out the exact curve values can be a chore.
This is the current state of easing in CSS. We’ll get to the shiny, new stuff in a bit. But first, I think it’s a good idea to revisit how easing functions influence easing behavior in curvatures.
Visualizing Easing Curves #
We can visualize different easings with a graphical curve. The site easings.net does a good job of providing options that can be used with the cubic-bezier()
timing function.
Easing curves can also be viewed in Chromium DevTools, allowing you to inspect any curve applied to a transition or animation.
Getting “Extra” Easing With linear()
#
But
what if you need something a little extra than what’s available? For
example, what about a bounce? Or a spring? These are the types of easing
functions that we are unable to achieve with a cubic-bezier()
curve.
This is where the new linear()
easing function comes into play, pioneered by Jake Archibald and defined in the CSS Easing Level 2 specification, which is currently in the Editor’s Draft. MDN describes it well:
The linear()
function defines a piecewise linear function that interpolates linearly
between its points, allowing you to approximate more complex animations
like bounce and elastic effects.
In other words, it’s a way to plot a graph with as many points as you like to define a custom easing curve. That’s pretty special and opens new possibilities we could not do before with CSS animations and transitions.
For example, the easing for a bounce could look like this:
Here’s how that looks in action:
A gentle reminder that browser support is limited to Chrome and Firefox, so be sure to view the demo in one of those browsers. We’re only waiting on Safari at the moment, so we’re almost there!
“I’m not working all that out.” #
That
easing example sure looks like a lot of numbers plucked straight out of
thin air, doesn’t it? As far as complexity goes, we’re looking at
something that’s as scary as cubic-bezier()
at first
glance. The good thing is, once you’ve defined an ease, you’re unlikely
to have to touch it again… at least for a while. It’s pretty much a
set-it-and-forget-it sort of thing.
But how do we get the numbers in the first place? Jake, the clever mind behind linear()
, put together an online generator
that does all the heavy lifting for us. In fact, I got the easing
values for the bounce demo straight from Jake’s handy tool. Here is a permalink to the output.
Where’s All Of This Going? #
For as long as I can remember, if I’ve needed some special easing for the work I’m doing, GreenSock has been my go-to solution. Its ease visualizer is one of my favorite examples of interactive documentation.
As soon as I heard about the linear()
function, my mind went straight to: “How can I convert GreenSock eases to CSS?”
Imagine how awesome it would be to have access to a popular set of
eases that can be used directly in CSS without reaching for JavaScript.
GreenSock’s
visualizer accepts JavaScript or an SVG path. So, my first thought was
to open DevTools, grab the SVG paths from the visualizer, and drop them
into the tool. However, I encountered a hurdle because I needed to scale
down the path coordinates for a viewBox
of 0 0 1 1
. GreenSock’s visualizer has a viewBox
set to 0 0 500 500
.
I wrote a function to convert the coordinates and reverse the path to
go in the right direction. Then, I reached out to Jake with some
questions about the generator. The code is available on GitHub.
In my head, I thought the SVG route made sense. But, then I created a path that wouldn’t work in the tool. So, I reached back out to Jake, and we both thought the issue was a bug in the tool.
Jake
then asked, “Why do you need to go via SVG?”. His question was spot on!
The JavaScript input for the tool expects an easing function. An easing
function maps time to a progress value. And we can get the easing
functions straight out of GreenSock and pass them to the generator. Jake
managed to dig the back
easing function out of the GreenSock GitHub repo and create the easing I was originally after.
Generating GSAP Eases For CSS #
Now that I’ve given you a bunch of context, we have all the parts of the puzzle we need to make something that can convert GSAP easing to CSS code.
First, we extract the parts from Jake’s linear()
generator tool into a script. The idea is to loop over a set of keys and generate a block of CSS with linear()
easings. GreenSock has a lovely utility method called parseEase
. It takes a string and returns the easing function. The accepted strings are the GreenSock easing functions.
As this loops over an object with different easing functions, we can pass them into the extracted code from the tool. We modify that extracted code to our needs.
The functions we extracted from the linear generator do different things:
processEase
This is a modified version ofprocessScriptData
. It takes the easing functions and returns points for our graph.useOptimizedPoints
This optimizes those points based on thesimplied
androunded
values. This was where I learned about the Douglas Peucker algorithm from Jake.useLinearSyntax
This takes the optimized points and returns the values for thelinear()
function.useFriendlyLinearCode
This takes thelinear
values and returns a CSS string that we can use with the ease’s custom property name.
It’s worth noting that I’ve tried not to touch these too much. But it’s also worth digging in and dropping in a breakpoint or console.info
at various spots to understand how things are working.
After running things, the result gives us CSS variables containing the linear()
easing functions and values. The following example shows the elastic and bounce eases.
We’re able to adjust this output to our heart’s desire with different keys or accuracy. The really cool thing is that we can now drop these GreenSock eases into CSS!
How To Get Your Very Own CSS linear()
Ease #
Here’s a little tool I put together. It allows you to select the type of animation you want, apply a linear()
ease to it, and determine its speed. From there, flip the card over to view and copy the generated code.
In cases where linear()
isn’t supported by a browser, we could use a fallback value for the ease using @supports
:
And just for fun, here’s a demo that takes the GreenSock ease string as an input and gives you the linear()
function back. Try something like elastic.out(1, 0.1)
and see what happens!
Bonus: Linear Eases For Tailwind #
You don’t think we’d leave out those of you who use Tailwind, do you? Not a chance. In fact, extending Tailwind with our custom eases isn’t much trouble at all.
I’ve put something together in Tailwind Play for you to see this in action and do some experimenting. This will give you classes like animation-timing-bounce-out
and ease-bounce-out
.
Conclusion #
CSS
has traditionally only provided limited control over the timing of
animations and transitions. The only way to get the behavior we wanted
was to reach for JavaScript solutions. Well, that’s soon going to
change, thanks to the easing superpowers of the new linear()
timing function
that’s defined in the CSS Easing Level 2 draft specification. Be sure
to drop those transitions into your demos, and I look forward to seeing
what you do with them!
Stay awesome. ┬┴┬┴┤•ᴥ•ʔ├┬┴┬┴
No comments:
Post a Comment