Monday, October 17, 2022
HomeProgrammingPure CSS Bezier Curve Movement Paths | CSS-Tips

Pure CSS Bezier Curve Movement Paths | CSS-Tips


Are you a Bezier curve lover like I’m?

Moreover being elegant, Bezier curves have good mathematical properties as a consequence of their definition and development. No surprise they’re broadly utilized in so many areas:

  • As a drawing/design software: They’re usually refered to as “paths” in vector drawing software program.
  • As a format of representing curves: They’re utilized in SVG, fonts and lots of different vector graphic codecs.
  • As a mathematical operate: Usually used to regulate animation timing.

Now, how about utilizing Bezier curves as movement paths with CSS?

Fast Recap

Relying on the context, when referring to a “Bezier curve”, we frequently assume a 2D cubic Bezier curve.

Such a curve is outlined by 4 factors:

Bezier curve
MarianSigler, Public area, by way of Wikimedia Commons

Observe: On this article, we usually seek advice from P0 and P3 as endpoints, P1 and P2 as management factors.

The phrase “cubic” means the underlying operate of the curve is a cubic polynomial. There are additionally “quadratic” Bezier curves, that are comparable, however with one fewer management level.

The Downside

Say you’re given an arbitrary 2D cubic Beizer curve, how would you animate a component with pure CSS animation, such that it strikes exactly alongside the curve?

For instance, how would you recreate this animation?

On this article we’ll discover three strategies with totally different flavors. For every answer we’ll current an interactive demo, then clarify the way it works. There are many mathematical calculations and proofs behind the scene, however don’t fear, we won’t go very deep.

Let’s begin!

Technique 1: Time Warp

Right here’s the essential concept:

  • Arrange @keyframes to maneuver the component from one endpoint of the curve to the opposite.
  • Distort the time for every coordinate individually, utilizing animation-timing-function.

Observe: There are many examples and explanations in Temani Afif’s article (2021).

Utilizing the cubic-bezier() operate with appropriate parameters, we are able to create a movement path of any cubic Bezier curve:

This demo exhibits a pure CSS animation. But canvas and JavaScript are used, which serve two functions:

  • Visualize the underlying Bezier curve (pink curve).
  • Permit adjusting the curve with the standard “path” UI.

You’ll be able to drag the 2 endpoints (black dots) and the 2 management factors (black squares). The JavaScript code will replace the animation accordingly, by updating just a few CSS variables.

Observe: Right here’s a pure CSS model for reference.

The way it works

Suppose the specified cubic Bezier curve is outlined by 4 factors: p0, p1, p2, and p3. We arrange CSS guidelines as following:

/* pseudo CSS code */
div {
  animation-name: move-x, move-y;
  /*
    Outline:
    f(x, a, b) = (x - a) / (b - a)
    qx1 = f(p1.x, p0.x, p3.x)
    qx2 = f(p2.x, p0.x, p3.x)
    qy1 = f(p1.y, p0.y, p3.y)
    qy2 = f(p2.y, p0.y, p3.y)
  */
  animation-timing-function: 
    cubic-bezier(1/3, qx1, 2/3, qx1),
    cubic-bezier(1/3, qy1, 2/3, qy2);
}

@keyframes move-x {
  from {
    left: p0.x;
  }
  to {
    left: p3.x;
  }
}

@keyframes move-y {
  from {
    prime: p0.y;
  }
  to {
    prime: p3.y;
  }
}

The @keyframes guidelines move-x and move-y decide the beginning and ending areas of the component. In animation-timing-function we have now two magical cubic-bezier() features, the parameters are calculated such that each prime and left at all times have the proper values at any time.

I’ll skip the maths, however I drafted a short proof right here, to your curious math minds.

Discussions

This technique ought to work nicely for many instances. You’ll be able to even make a 3D cubic Bezier curve, by introducing one other animation for the z worth.

Nonetheless there are just a few minor caveats:

  • It doesn’t work when each endpoints lie on a horizontal or vertical line, due to the division-by-zero error.

Observe: In observe, you possibly can simply add a tiny offset as a workaround.

  • It doesn’t help Bezier curves with an order increased than 3.
  • Choices for animation timing are restricted.
    • We use 1/3 and 2/3 above to attain a linear timing.
    • You’ll be able to tweak each values to regulate the timing, however it’s restricted in contrast with different strategies. Extra on this later.

Technique 2: Competing Animations

As a warm-up, think about a component with two animations:

div {
  animation-name: move1, move2;
}

What’s the movement path of the component, if the animations are outlined as following:

@keyframes move1 {
  to {
    left: 256px;
  }
}

@keyframes move2 {
  to {
    prime: 256px;
  }
}

As you could have guessed, it strikes diagonally:

Now, what if the animations are outlined like this as an alternative:

@keyframes move1 {
  to {
    remodel: translateX(256px);
  }
}

@keyframes move2 {
  to {
    remodel: translateY(256px);
  }
}

“Aha, you can’t trick me!” you may say, as you seen that each animations are altering the identical property, “move2 should override move1 like this:”

Nicely, earlier I had thought so, too. However truly we get this:

The trick is that move2 doesn’t have a from body, which implies the beginning place is animated by move1.

Within the following demo, the beginning place of transfer2 is visualized because the transferring blue dot:

Quadratic Bezier Curves

The demo proper above resembles the development of a quadratic Bezier curve:

Bézier 2 big
Phil Tregoning, Public area, by way of Wikimedia Commons

However they appear totally different. The development has three linearly transferring dots (two inexperienced, one black), however our demo has solely two (the blue dot and the goal component).

Truly the movement path within the demo is a quadratic Bezier curve, we simply have to tune the keyframes rigorously. I’ll skip the maths and simply reveal the magic:

Suppose a quadratic Bezier curve is outlined by factors p0, p1, and p2. With a view to transfer a component alongside the curve, we do the next:

/* pseudo-CSS code */
div {
  animation-name: move1, move2;
}

@keyframes move1 {
  from {
    remodel: translate3d(p0.x, p0.y, p0.z);
  }
  /* outline q1 = (2 * p1 - p2) */
  to {
    remodel: translate3d(q1.x, q1.y, q1.z);
  }
}

@keyframes move2 {
  to {
    remodel: translate3d(p2.x, p2.y, p2.z);
  }
}

Just like the demo of Technique 1, you possibly can view or alter the curve. Moreover, the demo additionally exhibits two extra items of data:

  • The mathematical development (grey transferring components)
  • The CSS animations (blue components)

Each could be toggled utilizing the checkboxes.

Cubic Bezier Curves

This technique works for cubic Bezier curves as nicely. If the curve is outlined by factors p0, p1, p2, and p3. The animations ought to be outlined like this:

/* pseudo-CSS code */
div {
  animation-name: move1, move2, move3;
}

@keyframes move1 {
  from {
    remodel: translate3d(p0.x, p0.y, p0.z);
  }
  /* outline q1 = (3 * p1 - 3 * p2 + p3) */
  to {
    remodel: translate3d(q1.x, q1.y, q1.z);
  }
}

@keyframes move2 {
  /* outline q2 = (3 * p2 - 2 * p3) */
  to {
    remodel: translate3d(q2.x, q2.y, q2.z);
  }
}

@keyframes move3 {
  to {
    remodel: translate3d(p3.x, p3.y, p3.z);
  }
}

Extensions

What about 3D Bezier Curves? Truly, the reality is, all of the earlier examples have been 3D curves, we simply by no means bothered with the z values.

What about higher-order Bezier curves? I’m 90% certain that the strategy could be naturally prolonged to increased orders. Please let me know if in case you have labored out the formulation for fourth-order Bezier curves, and even higher, a generic formulation for Bezier curves of order N.

Technique 3: Normal Bezier Curve Development

The mathematical development of Bezier Curves already offers us a very good trace.

Bézier 3 big
Phil Tregoning, Public area, by way of Wikimedia Commons

Step-by-step, we are able to decide the coordinates of all transferring dots. First, we decide the situation of the inexperienced dot that’s transferring between p0 and p1:

@keyframes green0 {
  from {
    --green0x: var(--p0x);
    --green0y: var(--p0y);
  }
  to {
    --green0x: var(--p1x);
    --green0y: var(--p1y);
  }
}

Extra inexperienced dots could be constructed in an analogous method.

Subsequent, we are able to decide the situation of a blue dot like this:

@keyframes blue0 {
  from {
    --blue0x: var(--green0x);
    --blue0y: var(--green0y);
  }
  to {
    --blue0x: var(--green1x);
    --blue0y: var(--green1y);
  }
}

Rinse and repeat, finally we’ll get the specified curve.

Just like Technique 2, with this technique we are able to simply construct a 3D Bezier Curve. Additionally it is intuitive to increase the strategy for higher-order Bezier curves.

The one draw back is the utilization of @property, which isn’t supported by all browsers.

Animation Timing

All of the examples to date have the “linear” timing, what about easing or different timing features?

Observe: By “linear” we imply the variable t of the curve linearly modifications from 0 to 1. In different phrases, t is identical as animation progress.

animation-timing-function isn’t utilized in Technique 2 and Technique 3. Like different CSS animations, we are able to use any supported timing operate right here, however we have to apply the identical operate for all animations (move1, move2, and move3) on the similar time.

Right here’s an instance of animation-timing-function: cubic-bezier(1, 0.1, 0, 0.9):

And right here’s the way it appears like with animation-timing-function: steps(18, finish):

Alternatively, Technique 1 is trickier, as a result of it already makes use of a cubic-bezier(u1, v1, u2, v2) timing operate. Within the examples above we have now u1=1/3 and u2=2/3. Actually we are able to tweak the timing by altering each parameters. Once more, all animations (e.g., move-x and move-y) should have the identical values of u1 and u2.

Right here’s the way it appears like when u1=1 and u2=0:

With Technique 2, we are able to obtain precisely the identical impact by setting animation-timing-function to cubic-bezier(1, 0.333, 0, 0.667):

Actually, it really works in a extra basic method:

Suppose that we’re given a cubic Bezier curve, and we created two animations for the curve with Technique 1 and Technique 2 respectively. For any legitimate values of u1 and u2, the next two setups have the identical animation timing:

  • Technique 1 with animation-timing-function: cubic-bezier(u1, *, u2, *).
  • Technique 2 with animation-timing-function: cubic-bezier(u1, 1/3, u2, 2/3).

Now we see why Technique 1 is “restricted”: with Technique 1 we are able to solely cubic-bezier() with two parameters, however with Technique 2 and Technique 3 we are able to use any CSS animation-timing-function.

Conclusions

On this article, we mentioned 3 totally different strategies of transferring parts exactly alongside a Bezier curve, utilizing solely CSS animations.

Whereas all 3 strategies are roughly sensible, they’ve their very own professionals and cons:

  • Technique 1 could be extra intuitive for these accustomed to the timing operate hack. However it’s much less versatile with animation timing.
  • Technique 2 has quite simple CSS guidelines. Any CSS timing operate could be utilized immediately. Nonetheless, it could possibly be exhausting to recollect the formulation.
  • Technique 3 make extra sense for these accustomed to the maths development of Bezier curves. Animation timing can also be versatile. Alternatively, not all fashionable browsers are supported, due the utilization of @property.

That’s all! I hope you discover this text attention-grabbing. Please let me know your ideas!

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments