all-threads-bot

Frontender`s Spectre

Having Fun with Animations: Mimicking a Sine Wave with cubic-bezier()

16 марта 2025 г., 14:33
Luis Torres
5 min read
·
20 hours ago

--

After our pit stop exploring Dynamic CSS, it’s time to have some fun! This article is for the curious minds who love pushing CSS to unexpected places. Today, we’ll explore animations, transitions, and cubic-bezier() by breaking down an incredible deep dive by Temani Afif — with a few twists of our own.

The Setup

Let’s start simple:

1️⃣ We begin with a square and a small symbol in one corner. This will help us track how the square moves while animating.

Square with a corner
<div class="square">  <div class="corner"></div></div>

2️⃣ Our goal? Animate the element along a sine wave! This means our square will move from its initial position to a max point, then a min point, then back to its starting position.

sine curve

If you remember how cubic-bezier() works, the curve defines how an element’s property changes over time. Since the start and end points are always fixed at (0,0) and (1,1), you might think it’s impossible to create a sine-like motion with cubic-bezier().

cubic-bezier curve

But what if… we move p1 and p2 very, very, very far in opposite directions while making the property change very, very, very small? Boom! We now have a curve that mimics a sine wave.

cubic-bezier(.5,-900,.5,900)

The Curiosity Begins

Step 1: Moving Horizontally

First, let’s translate our square along the x-axis using our modified cubic-bezier curve.

@property --translateX {  syntax: '<length>';   initial-value: 0px;  inherits: false;}.square {  translate: var(--translateX) 0px;}.animate {  animation: _translateX 2s;  animation-timing-function: cubic-bezier(.5,-900,.5,900);  animation-iteration-count: infinite;}@keyframes _translateX {  to {    --translateX: 1px;  }}
translate along the horizontal axis

Step 2: Moving Vertically

Now, let’s do the same along the y-axis, but with a smaller property change to keep the motion subtle.

translate along the vertical axis

Step 3: The Infinity Path

If we combine both x and y translations, adjusting their timing slightly… we should see our square follow the shape of an infinity sign (∞).

@property --translateX {  syntax: '<length>';   initial-value: 0px;  inherits: false;}@property --translateY {  syntax: '<length>';   initial-value: 0px;  inherits: false;}.square {  translate: var(--translateX) var(--translateY);}.animate {  animation: _translateX 2s, _translateY 1s;  animation-timing-function: cubic-bezier(.5,-900,.5,900);  animation-iteration-count: infinite;}@keyframes _translateX {  to {    --translateX: 1px;  }}@keyframes _translateY {  to {    --translateY: .2px;  }}
translates along infinity sign path

Don’t tell me that isn’t cool. 😎

Bend It Like Beckham! ⚽️

For those who don’t know, Bend it like Beckham refers to kicking a soccer ball with spin so that it curves mid-air. If you’ve been paying attention to our square, you may have noticed it never actually rotates as it moves.

Let’s change that.

Step 4: Adding Rotation

Let’s add a rotation to our square and make it spin 😵‍💫.

@property --rotate {  syntax: '<angle>';   initial-value: 0deg;  inherits: false;}.square {  transform: rotate(var(--rotate));}.animate {  animation: _rotate 1s;  animation-timing-function: linear;  animation-iteration-count: infinite;}@keyframes _rotate {  to {    --rotate: -360deg;  }}
square spinning

But we’re not stopping there! By rotating our square while it moves, we start to see something very interesting — it starts following unexpected and mesmerizing paths.

@property --rotate {  syntax: '<angle>';   initial-value: 0deg;  inherits: false;}@property --translate {  syntax: '<length>';   initial-value: 0px;  inherits: false;}.square {  transform: rotate(var(--rotate)) translate(var(--translate));}.animate {  animation: _rotate 1s, _translate 4s;  animation-timing-function: linear, cubic-bezier(.5,-900,.5,900);  animation-iteration-count: infinite;}@keyframes _rotate {  to {    --rotate: -360deg;  }}@keyframes _translate {  to {    --translate: 1px;  }}
square spinning while translating

Now, play with different animation durations, and you can create entirely new patterns!

In the next example the rotation is slower than the translation.

You can even chain multiple transforms together for some truly mind-bending motion paths.

Where Do We Go from Here?

I think we’ve had enough of smooth curves for now 😆. But if you’re curious, there’s still more to explore — like the steps() and linear() timing functions.

CSS is full of hidden gems — some well-known, others waiting to be uncovered. Next time, we’ll dive into more fascinating CSS functions and features that can reshape the way you think about styling.

Get ready to level up your CSS toolkit! 🚀