Pure CSS Bezier Curve Motion Paths
Now, how about using Bezier curves as motion paths with CSS?
Depending on the context, when referring to a “Bezier curve”, we often assume a 2D cubic Bezier curve.
Such a curve is defined by four points:
Note: In this article, we generally refer to
P3 as endpoints,
P2 as control points.
The word “cubic” means the underlying function of the curve is a cubic polynomial. There are also “quadratic” Bezier curves, which are similar, but with one fewer control point.
Say you are given an arbitrary 2D cubic Beizer curve, how would you animate an element with pure CSS animation, such that it moves precisely along the curve?
As an example, how would you recreate this animation?
In this article we will explore three methods with different flavors. For each solution we will present an interactive demo, then explain how it works. There are lots of mathematical calculations and proofs behind the scene, but don’t worry, we will not go very deep.
Here’s the basic idea:
cubic-bezier() function with correct parameters, we can create a motion path of any cubic Bezier curve:
Suppose the desired cubic Bezier curve is defined by four points:
p3. We set up CSS rules as following:
move-y determine the starting and finishing locations of the element. In
animation-timing-function we have two magical
cubic-bezier() functions, the parameters are calculated such that both
left always have the correct values at any time.
This method should work well for most cases. You can even make a 3D cubic Bezier curve, by introducing another animation for the
However there are a few minor caveats:
Note: In practice, you can just add a tiny offset as a workaround.
As a warm-up, imagine an element with two animations:
What is the motion path of the element, if the animations are defined as following:
As you may have guessed, it moves diagonally:
Now, what if the animations are defined like this instead:
“Aha, you cannot trick me!” you might say, as you noticed that both animations are changing the same property, “
move2 must override
move1 like this:”
Well, earlier I had thought so, too. But actually we get this:
The trick is that
move2 does not have a
from frame, which means the starting position is animated by
In the following demo, the starting position of
move2 is visualized as the moving blue dot:
The demo right above resembles the construction of a quadratic Bezier curve:
But they look different. The construction has three linearly moving dots (two green, one black), but our demo has only two (the blue dot and the target element).
Suppose a quadratic Bezier curve is defined by points
p2. In order to move an element along the curve, we do the following:
Similar to the demo of Method 1, you can view or adjust the curve. Additionally, the demo also shows two more pieces of information:
Both can be toggled using the checkboxes.
This method works for cubic Bezier curves as well. If the curve is defined by points
p3. The animations should be defined like this:
What about 3D Bezier Curves? Actually, the truth is, all the previous examples were 3D curves, we just never bothered with the
What about higher-order Bezier curves? I am 90% sure that the method can be naturally extended to higher orders. Please let me know if you have worked out the formula for fourth-order Bezier curves, or even better, a generic formula for Bezier curves of order N.
Step-by-step, we can determine the coordinates of all moving dots. First, we determine the location of the green dot that is moving between
Additional green dots can be constructed in a similar way.
Next, we can determine the location of a blue dot like this:
Rinse and repeat, eventually we will get the desired curve.
Similar to Method 2, with this method we can easily build a 3D Bezier Curve. It is also intuitive to extend the method for higher-order Bezier curves.
The only downside is the usage of
@property, which is not supported by all browsers.
All the examples so far have the “linear” timing, what about easing or other timing functions?
animation-timing-function is never used in Method 2 and Method 3. Like other CSS animations, we can use any supported timing function here, but we need to apply the same function for all animations (
move3) at the same time.
Here’s an example of
animation-timing-function: cubic-bezier(1, 0.1, 0, 0.9):
And here’s how it looks like with
animation-timing-function: steps(18, end):
On the other hand, Method 1 is trickier, because it already uses a
cubic-bezier(u1, v1, u2, v2) timing function. In the examples above we have
u2=2/3. In fact we can tweak the timing by changing both parameters. Again, all animations (e.g.,
move-y) must have the same values of
Here’s how it looks like when
With Method 2, we can achieve exactly the same effect by setting
cubic-bezier(1, 0.333, 0, 0.667):
In fact, it works in a more general way:
Suppose that we are given a cubic Bezier curve, and we created two animations for the curve with Method 1 and Method 2 respectively. For any valid values of
u2, the following two setups have the same animation timing:
Now we see why Method 1 is “limited”: with Method 1 we can only
cubic-bezier() with two parameters, but with Method 2 and Method 3 we can use any CSS
In this article, we discussed 3 different methods of moving elements precisely along a Bezier curve, using only CSS animations.
While all 3 methods are more or less practical, they have their own pros and cons:
That’s all! I hope you find this article interesting. Please let me know your thoughts!
If you need help creating a digital marketing strategy for your business, don’t hesitate to contact one of Digidude’s consultants.