How to implement Confetti animation

We are currently focused on implementing animation for better User Experience. One of the animations that we implemented lately is Confetti.

We need Confetti for a celebration!

There were some learnings while writing animation of Confetti. I will explain how to do it in this article.

Confetti animation prototype

Our designer provided the prototype as below using Anima which exports her sketch and automatically generates code.

Prototype

We found out that we cannot simply auto-generated code from the Anima app. So we decided to create animation by ourselves.

There were two steps to create animation capturing real confetti movement which is 1) Confetti is thrown and 2) Confetti is falling down.

Both speeds are different. When we throw Confetti, they reach to the top quickly and they will fall down slowly.

The speeds of each step should vary as below.

1) Confetti is thrown (Fade-in animation)

2) Confetti is falling down (Fade-out animation)

Use cubic-bezer

Normally adding eitherlinear or ease in transition-timing-functionis sufficient for simple animations. When it comes to our Confetti animation, we know that we have to add customized cubic-bezier.

There is a cool website where you can create your desirable cubic-bezier. As there are two different steps in our Confetti animation, I tried to implement both cases in one cubic-bezier value as below.

http://cubic-bezier.com

Here is a piece of code. I used avalue cubic-bezier(.17,.5,.9,.02) which I got from the above website.

@keyframes confetti-fade-in-and-out {
15% {
opacity: 0;
margin-top: 0;
}
35% {
opacity: 1;
margin-top: -50px;
}
55% {
opacity: 1;
margin-top: -50px;
}
100% {
opacity: 0;
margin-top: 0;
}
}

@mixin confetti-animation() {
animation: confetti-fade-in-and-out 3.2s cubic-bezier(.17,.5,.9,.02) ;
position: absolute;
opacity: 0;
}

This code generates the following animation.

First experiment

As you can see, linear-in for fade-in animation and ease-out for fade-out animation are not visible and it’s still far from the prototype.

We learned that we cannot pack two timing/speed in one cubic-bezier. So we decided to split it into two.

Use two keyframes

In order to have different timing and speed for Confetti movement, we created two keyframes. I wrapped Confetti img with div and pass keyframes to each of the elements.

<div className=’confetti-wrapper’>
<img src=’./img/Confetti.svg’ className=’confetti’ />
</div>

For fade-in animation, we used cubic-bezier(0,0.88,0.51,1) We got this value from the prototype that our designer created in Anima.

@keyframes confetti-fade-in {
15% {
opacity: 0;
margin-top: 10px;
}
100% {
opacity: 1;
margin-top: -50px;
}
}

@mixin confetti-fade-in() {
animation: confetti-fade-in 3.2s cubic-bezier(0,0.88,0.51,1);
position: absolute;
opacity: 0;
}

For fade-out animation, we used cubic-bezier(0.84,0,1,1)

@keyframes confetti-fade-out {
0% {
opacity: 1;
margin-top: -50px;
}
100% {
opacity: 0;
margin-top: 10px;
}
}

@mixin confetti-fade-out() {
animation: confetti-fade-out 3.2s cubic-bezier(0.84,0,1,1);
position: absolute;
opacity: 0;
}

At first, we added delay for fade-out animation, however, it didn’t work.

In the end, each fade-in and fade-out animation works perfectly without adding any delay and using the same animation duration.

Result

Add two keyframes to animation function

I was content with the result above, my colleague suggested me to add two keyframes in animation function.

Here is the code.

@keyframes confetti-fade-in {
15% {
opacity: 0;
margin-top: 0;
}
100% {
opacity: 1;
margin-top: -50px;
}
}

@keyframes confetti-fade-out {
0% {
opacity: 1;
margin-top: -50px;
}
100% {
opacity: 0;
margin-top: 0;
}
}

@mixin confetti-fade-in-and-out () {
animation: confetti-fade-in 1.6s cubic-bezier(0,0.88,0.51,1), confetti-fade-out 1.6s cubic-bezier(.84,0,1,1) 1.6s;
position: absolute;
opacity: 0;
}

First confetti-fade-in 1.6s cubic-bezier(0,0.88,0.51,1) will be called. As 1.6s delay is added in the last, confetti-fade-out 1.6s cubic-bezier(0.84,0,1,1) will be called after fade-in animation.

Using this solution, we don’t have to add <div> wrapper to have two keyframes. Simple and concise!

Summary

Let me summarise what we learned along the way.

  • Making use of cubic-bezier to create customized animation
  • It’s possible to add two keyframes into one animation function to have different timing and speed of the animation

I hope this article helps you to unlock your limitation to create your desirable animations!


If you are curious about how we make use of animation for better UX, my colleague UX designer wrote about it in the following article.

Emotional Animation in UX — why, when and how to design it