惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Threatpost
博客园 - 叶小钗
T
The Blog of Author Tim Ferriss
Recent Announcements
Recent Announcements
D
DataBreaches.Net
The Cloudflare Blog
阮一峰的网络日志
阮一峰的网络日志
罗磊的独立博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
N
Netflix TechBlog - Medium
Microsoft Azure Blog
Microsoft Azure Blog
Microsoft Security Blog
Microsoft Security Blog
B
Blog
U
Unit 42
有赞技术团队
有赞技术团队
博客园 - 聂微东
GbyAI
GbyAI
宝玉的分享
宝玉的分享
F
Full Disclosure
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
MyScale Blog
MyScale Blog
Jina AI
Jina AI
Martin Fowler
Martin Fowler
IT之家
IT之家
酷 壳 – CoolShell
酷 壳 – CoolShell
D
Docker
P
Proofpoint News Feed
A
About on SuperTechFans
I
InfoQ
博客园 - 【当耐特】
C
Check Point Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
P
Privacy & Cybersecurity Law Blog
T
Threat Research - Cisco Blogs
Y
Y Combinator Blog
Project Zero
Project Zero
WordPress大学
WordPress大学
小众软件
小众软件
AWS News Blog
AWS News Blog
博客园 - 司徒正美
T
The Exploit Database - CXSecurity.com
L
LINUX DO - 热门话题
I
Intezer
Engineering at Meta
Engineering at Meta
C
CXSECURITY Database RSS Feed - CXSecurity.com
J
Java Code Geeks
T
Tenable Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Last Week in AI
Last Week in AI
C
CERT Recently Published Vulnerability Notes

CSS Articles by Temani Afif

Get Ready For the Powerful CSS border-shape Property! | CSS-Tricks Let’s Play With Gap Decorations! How to Control Infinite CSS Animations (Part 2 of 2) How to Control Infinite CSS Animations (Part 1 of 2) Two Circles, One Arrow, and Anchor Positioning Making a Responsive Pyramidal Grid With Modern CSS | CSS-Tricks How to Create a CSS-only Elastic Text Effect Making Complex CSS Shapes Using shape() | CSS-Tricks Responsive Hexagon Grid Using Modern CSS | CSS-Tricks Responsive List of Avatars Using Modern CSS (Part 2) | CSS-Tricks Responsive List of Avatars Using Modern CSS (Part 1) | CSS-Tricks Perfectly Pointed Tooltips: To The Corners Perfectly Pointed Tooltips: All Four Sides Perfectly Pointed Tooltips: A Foundation Sequential linear() Animation With N Elements | CSS-Tricks Infinite Marquee Animation using Modern CSS Better CSS Shapes Using shape() — Part 4: Close and Move | CSS-Tricks Drawing CSS Shapes using corner-shape Better CSS Shapes Using shape() — Part 3: Curves | CSS-Tricks Better CSS Shapes Using shape() — Part 2: More on Arcs | CSS-Tricks Better CSS Shapes Using shape() — Part 1: Lines and Arcs | CSS-Tricks Creating Blob Shapes using clip-path: shape() Creating Flower Shapes using clip-path: shape() Custom progress element using the attr() function A CSS-Only Star Rating Component and More! (Part 2) | CSS-Tricks A CSS-Only Star Rating Component and More! (Part 1) | CSS-Tricks How to Create Wavy Boxes Using CSS Full-Bleed Layout with Modern CSS Fancy Menu Navigation Using Anchor Positioning | CSS-Tricks How to Create a Zig-Zag Box Using CSS How to Create Zig-Zag CSS Loaders Using One Element Custom Progress Element Using Anchor Positioning & Scroll-Driven Animations How to Create Filling CSS Loaders Using One Element How to Create Curved-Edge and Rounded-Edge Shapes Using CSS CSS Tricks That Use Only One Gradient | CSS-Tricks How to create Shapes with Inner Curves using CSS Mask Custom Range Slider Using Anchor Positioning & Scroll-Driven Animations How to Get the Width/Height of Any Element in Only CSS How Keyboard Navigation Works in a CSS Game How To Create Cut-Out Shapes using The clip-path property The Modern Guide For Making CSS Shapes — Smashing Magazine css-shape.com: The Ultimate Collection of CSS-only Shapes ⚡️ Sliding 3D Image Frames In CSS — Smashing Magazine CSS Tricks To Master The clip-path Property Creating Wavy Circles with Fancy Animations in CSS Modern CSS Tooltips And Speech Bubbles (Part 2) — Smashing Magazine Do you need a Tooltip or a Speech Bubble? I have created 100 using CSS 😲 Modern CSS Tooltips And Speech Bubbles (Part 1) — Smashing Magazine Creating Flower Shapes using CSS Mask & Trigonometric Functions CSS Shapes: The Triangle The Complex But Awesome CSS border-image Property — Smashing Magazine CSS Tricks to add 3D Effects to your Text CSS Responsive Multi-Line Ribbon Shapes (Part 2) — Smashing Magazine CSS Responsive Multi-Line Ribbon Shapes (Part 1) — Smashing Magazine I have made 100+ CSS-only Ribbon Shapes | The Perfect Collection 🎀 How to create a CSS-only infinite scroll animation Re-Creating The Pop-Out Hover Effect With Modern CSS (Part 2) — Smashing Magazine Re-Creating The Pop-Out Hover Effect With Modern CSS (Part 1) — Smashing Magazine How to Create CSS Ribbon Shapes with a Single Element CSS Shapes: The Ribbon Revealing Images With CSS Mask Animations — Smashing Magazine css-loaders.com: The Biggest Collection of Loading Animations (more than 500 🤯) How To Define An Array Of Colors With CSS — Smashing Magazine CSS effects on images II Shines, Perspective, And Rotations: Fancy CSS 3D Effects For Images — Smashing Magazine What's your Lucky CSS Pattern? Check It Now! How to Add a CSS Reveal Animation to Your Images Modern Layouts using CSS Grid I created 100+ unique CSS patterns | The best collection 🤩 How to Create a Custom Range Slider Using CSS CSS Shapes: The Heart CSS Shapes: Polygon & Starburst A Text Reveal Animation using CSS CSS Tip: learn CSS the easy way! How to build a CSS-only accordion How to create Breadcrumb Navigation with CSS Different Ways to Get CSS Gradient Shadows | CSS-Tricks A CSS-only responsive Stepper component A Fancy Hover Effect For Your Avatar | CSS-Tricks How to make a zoom effect using CSS Creating a Custom Cursor using CSS CSS Infinite 3D Sliders | CSS-Tricks CSS Infinite Slider Flipping Through Polaroid Images | CSS-Tricks How to create a responsive sidebar menu using CSS CSS Infinite and Circular Rotating Image Slider | CSS-Tricks Making Static Noise From a Weird CSS Gradient Bug | CSS-Tricks CSS Grid and Custom Shapes, Part 3 | CSS-Tricks Fancy Image Decorations: Outlines and Complex Animations | CSS-Tricks Fancy Image Decorations: Masks and Advanced Hover Effects | CSS-Tricks Fancy Image Decorations: Single Element Magic | CSS-Tricks How to create an infinite image slider using CSS How to Create Wavy Shapes & Patterns in CSS | CSS-Tricks How I Made a Pure CSS Puzzle Game | CSS-Tricks How to create a Tooltip/Speech Bubble using CSS CSS Grid and Custom Shapes, Part 2 | CSS-Tricks CSS Grid and Custom Shapes, Part 1 | CSS-Tricks Zooming Images in a Grid Layout | CSS-Tricks How to create a CSS-only loader with one element Exploring CSS Grid’s Implicit Grid and Auto-Placement Powers | CSS-Tricks How to create background pattern using CSS & conic-gradient
Advanced CSS Animation Using cubic-bezier() | CSS-Tricks
Temani Afif · 2021-05-13 · via CSS Articles by Temani Afif

When dealing with complex CSS animations, there is a tendency to create expansive @keyframes with lots of declarations. There are a couple of tricks though that I want to talk about that might help make things easier, while staying in vanilla CSS:

  1. Multiple animations
  2. Timing functions

The first one is more widely used and familiar but the second one is less common. There could be good reasons for that — chaining animations with commas is relatively easier than grokking the various timing functions that are available to us and what they do. There’s one especially neat timing function that gives us total control to create custom timing functions. That would be cubic-bezier() and in this post I will show you the power of it and how it can be used to create fancy animation without too much complexity.

Let’s start with a basic example showing how we can move a ball around in interesting directions, like an infinity (∞) shape:

As you can see, there is no complex code — only two keyframes and a cubic-bezier() function. And yet, a pretty complex-looking final infinity-shape animation is what we get.

Cool, right? Let’s dig into this!

The cubic-bezier() function

Let’s start with the official definition:

A cubic Bézier easing function is a type of easing function defined by four real numbers that specify the two control points, P1 and P2, of a cubic Bézier curve whose end points P0 and P3 are fixed at (0, 0) and (1, 1) respectively. The x coordinates of P1 and P2 are restricted to the range [0, 1].

The above curve defines how the output (y-axis) will behave based on the time (x-axis). Each axis has a range of [0, 1] (or [0% 100%] ). If we have an animation that lasts two-second (2s), then:

0 (0%) = 0s 
1 (100%) = 2s

If we want to animate left from 5px to 20px, then:

0 (0%) = 5px 
1 (100%) = 20px

X, the time, is always restricted to [0 1]; however, Y, the output, can go beyond [0 1].

My goal is to adjust P1 and P2 in order to create the following curves:

You may think this is impossible to achieve because, as stated in the definition, P0 and P3 are fixed at (0,0) and (1,1) meaning they cannot be on the same axis. That’s true, and we will use some math tricks to “approximate” them.

Parabolic curve

Let’s start with the following definition: cubic-bezier(0,1.5,1,1.5). That gives us the following curve:

cubic-bezier(0,1.5,1,1.5)

Our goal is to move (1,1) and make it at (0,1) which isn’t technically possible. So we will try to fake it.

We previously said that our range is [0 1] (or [0% 100%]) so let’s imagine the case when 0% is very close to 100%. If, for example, we want to animate top from 20px (0%) to 20.1px (100%) then we can say that both the initial and final states are equal.

Hm, but our element will not move at all, right?

Well, it will move a little because the Y value exceeds 20.1px (100%). But that’s not enough to give us perceptible movement:

Let’s update the curve and use cubic-bezier(0,4,1,4) instead. Notice how our curve is way taller than before:

cubic-bezier(0,4,1,4)

But yet, still no movement — even if the top value is crossing 3 (or 300%). Let’s try cubic-bezier(0,20,1,20):

cubic-bezier(0,20,1,20)

Yes! it started to move a little. Did you notice the evolution of the curve each time we increase the value? It’s making our point (1,1) “visually” closer to (0,1) when we zoom out to see the full curve and this is the trick.

By using cubic-bezier(0,V,1,V) where V is some very big value and both the initial and final states are very close together (or almost equal), we can simulate the parabolic curve.

An example is worth a thousand words:

I applied the “magic” cubic-bezier function in there to the top animation, plus a linear one applied to left. This gives us the curve we want.

Digging into the math

For those of you math-minded folks out there, we can break that explanation down further. A cubic bezier can be defined using the following formula:

P = (1−t)³P0 + 3(1−t)²tP1 + 3(1−t)t²P2 + t³P3

Each point is defined as follows: P0 = (0,0), P1 = (0,V), P2 = (1,V), and P3 = (1,1).

This gives us the two functions for x and y coordinates:

  • X(t) = 3(1−t)t² + t³ = 3t² - 2t³
  • Y(t) = 3(1−t)²tV +3(1−t)t²V + t³ = t³ - 3Vt² + 3Vt

V is our big value and t is within the range [0 1]. If we consider our previous example, Y(t) will give us the value of top while X(t) is the time progress. The points (X(t),Y(t)) will then define our curve.

Let’s find the maximum value of Y(t). For this, we need to find the value of t that will give us Y'(t) = 0 (when the derivative is equal to 0):

Y'(t) = 3t² - 6Vt + 3V

Y'(t) = 0 is a quadratic equation. I will skip the boring part and will give you the result, which is t = V - sqrt(V² - V).

When V is a large value, t will be equal to 0.5. So, Y(0.5) = Max and X(0.5) will be equal to 0.5. That means we reach the maximum value at the halfway point in the animation, which conforms to the parabolic curve we want.

Also, Y(0.5) will give us (1 + 6V)/8 and this will allow us to find the max value based on V. And since we will always use a big value for V, we can simplify to 6V/8 = 0.75V.

We used V = 500 in the last example, so the max value there would come out to 375 (or 37500%) and we get the following:

  • Initial state (0): top: 200px
  • Final state (1): top: 199.5px

There’s a difference of -0.5px between 0 and 1. Let’s call it the increment. For 375 (or 37500%) we have an equation of 375*-0.5px = -187.5px. Our animated element is reaching top: 12.5px (200px - 187.5px) and gives us the following animation:

top: 200px (at 0% of the time ) → top: 12.5px (at 50% of the time) → top: 199.5px (at 100% of the time) 

Or, expressed another way:

top: 200px (at 0%) → top: 12.5px (at 50%) → top: 200px (at 100%)

Let’s do the opposite logic. What value of V should we use to make our element reach top: 0px? The animation will be 200px → 0px → 199.5px, so we need -200px to reach 0px. Our increment is always equal to -0.5px. The max value will be equal to 200/0.5 = 400, so 0.75V = 400 which means V = 533.33.

Our element is touching the top!

Here is a figure that sums up that math we just did:

Parabolic Curve using cubic-bezier(0,V,1,V)

Sinusoidal curve

We will use almost the exact same trick to create a sinusoidal curve but with a different formula. This time we will use cubic-bezier(0.5,V,0.5,-V)

Like we did before, let’s see how the curve will evolve when we increase the value:

Three graphs from left to right, showing how the sinusoidal curve gets narrower as the V value increases.

I think you probably get the idea by now. Using a big value for V gets us close to a sinusoidal curve.

Here’s another one with a continuous animation — a real sinusoidal animation!

The math

Let’s get in the math for this one! Folllowing the same formula as before, we will get the following functions:

  • X(t) = 3/2(1−t)²t + 3/2(1−t)t² + t³ = (3/2)t - (3/2)t² + t³
  • Y(t) = 3(1−t)²tV - 3(1−t)t²V + t³ = (6V + 1)t³ - 9Vt² + 3Vt

This time we need to find the minimum and maximum values for Y(t). Y'(t) = 0 will give us two solutions. After solving for this:

Y'(t) = 3(6V + 1)t² - 18Vt + 3V = 0

…we get:

  • t' = (3V + sqrt(3V² - V))/(6V + 1)
  • t''= (3V - sqrt(3V² - V))/(6V + 1)

For a big value of V, we have t'=0.211 and t"=0.789. That means that Y(0.211) = Max and Y(0.789) = Min. That also means that X(0.211)= 0.26 and X(0.789) = 0.74. In other words, we reach the Max at 26% of the time and Min at 74% of the time.

Y(0.211) is equal to 0.289V and Y(0.789) to -0.289V. We got those values with some rounding considering that V is very big.

Our sinusoidal curve should also cross the x-axis (or Y(t) = 0) at half the time (or X(t) = 0.5). In order to prove this, we use the second derivate of Y(t) — which should be equal to 0 — so Y''(t) = 0.

Y''(t) = 6(6V + 1)t - 18V = 0

The solution is 3V/(6V + 1), and for a big V value, the solution is 0.5. That give us Y(0.5) = 0 and X(0.5) = 0.5 which confirms that our curve crosses the (0.5,0) point.

Now let’s consider the previous example and try to find the value of V that gets us back to top: 0%. We have:

  • Initial state (0): top: 50%
  • Final state (1): top: 49.9%
  • Increment: -0.1%

We need -50% to reach top: 0%, so 0.289V*-0.1% = -50% which gives us V = 1730.10.

As you can see, our element is touching the top and disappearing at the bottom because we have the following animation:

top: 50% → top: 0% → top: 50% → top: 100% → top: 50% → and so on ... 

A figure to sum up the calculation:

Sinusoidal Curve using cubic-bezier(0.5,V,0.5,-V)

And an example to illustrate all curves together:

Yes, you see four curves! If you look closely, you will notice that I am using two different animations, one going to 49.9% (an increment of -0.01%) and another going to 50.1% (an increment of +0.01%). By changing the sign of the increment, we control the direction of the curve. We can also control the other parameters of the cubic bezier (not the V one that should remain a big value) to create more variations from the same curves.

And below, an interactive demo:

Getting back to our example

Let’s get back to our initial example of a ball moving around in the shape of an infinity symbol. I simply combined two sinusoidal animations to make it work.

If we combine what we did previously with the concept of multiple animations, we can get astonishing results. Here again is the initial example, this time as an interactive demo. Change the values and see the magic:

Let’s go further and add a little CSS Houdini to the mix. We can animate a complex transform declaration thanks to @property (but CSS Houdini is limited to Chrome and Edge support at the moment).

What kind of drawings can you make with that? Here is a few that I was able to make:

And here is a spirograph animation:

And a version without CSS Houdini:

There’s a few things to take away from these examples:

  • Each keyframe is defined using only one declaration that contain the increment.
  • The position of the element and the animation are independent. We can easily place the element anywhere without the need to adjust the animation.
  • We made no calculations. There isn’t a ton of angles or pixel values. We only need a tiny value within the keyframe and a big value within the cubic-bezier() function.
  • The whole animation can be controlled just by adjusting the duration value.

What about transition?

The same technique can also be used with the CSS transition property since it follows the same logic when it comes to timing functions. This is great because we’re able to avoid keyframes when creating some complex hover effect.

Here’s what I made without keyframes:

Mario is jumping thanks to the parabolic curve. We needed no keyframes at all to create that shake animation on hover. The sinusoidal curve is perfectly capable of doing all the work.

Here is another version of Mario, this time using CSS Houdini. And, yep, he’s still jumping thanks to the parabolic curve:

For good measure, here are more fancy hover effects without keyframes (again, Chrome and Edge only):

That’s it!

Now you have some magic cubic-bezier() curves and the math behind them. The benefit, of course, is that custom timing functions like this let us do fancy animations without the complex keyframes we generally reach for.

I understand that not everyone is math-minded and that’s okay. There are tools to help, like Matthew Lein’s Ceaser, which lets you drag the curve points around to get what you need. And, if you don’t already have it bookmarked, cubic-bezier.com is another one. If you want to play with cubic-bezier outside the CSS world, I recommend desmos where you can see some math formulas.

Regardless of how you get your cubic-bezier() values, hopefully now you have a sense of their powers and how they can help make for nicer code in the process.