Chaining animations in CSS

Chaining animations in CSS

Cover photo credit: Sandy Miller from Unsplash.

Disclaimer: If you are new to animations in CSS Take a look at this guide Before reading this article.

I have always wanted to perform and or create stunning things with CSS, basically animation and transitions in CSS, after some time spent researching I decided to do something worthwhile with the results, hopefully, it helps you one way or the other.

So what do I mean by chaining animations? Do not let the words confuse you, what animation chaining simply means, is the ability for you to define and use multiple keyframes animations on a particular element giving you the fidelity to do so many awesome kinds of stuff within a timeframe. In this article, we'd be looking at an example, that shows a ball-like loader (having three balls).

Okay, let's get started.

So, since we want to have three balls arranged side by side together, we will be using flexbox to achieve this. Take a look at the HTML structure below.

       <html>
           <head>
                <title>Dancing Balls</title>
           </head>
           <body>
                <div class="balls flex">
                     <div class="ball zero"></div>
                     <div class="ball one"></div>
                     <div class="ball two"></div>
                </div>
           </body>
      </html>

The markup above shows the structure. The first div with the balls class attribute is the parent element that houses the balls. Theflex class attribute is just to enable styling easy for me, but you can choose not to use the flex attribute, whichever way you choose to achieve your result is fine. Now let's see the style for the HTML structure.

.flex {
    display: flex;
}

body {
  background: #f7f0f5;
  overflow-x: hidden;
  overflow-y: hidden;
}

.ball {
    width: 30px;
    height: 30px;
    background: #0a8754;
    border-radius: 50%;
}

.balls {
    justify-content: center;
    opacity: 0;
    margin-left: -8%;
    margin-top: 15%;
}

.balls > div {
    margin: .3em .4em;
}

The styles above give the balls the spacing, shape, background-color and the right alignments. The reason why both overflows of the body were set to hidden is a result of the balls trying to move out of the browser window, setting them that way hides the scrollbars that pop out every time that happens. You can try these styles to the results, once you're done, come back here, let's ride on!

We have our loading balls already in the browser, but they're just static, doing nothing. Let's add some interactivity by defining our keyframes.

@keyframes oscillate {  // moves the element (balls) top to bottom 
    0% {
        transform: translateY(0px);
    } 50% {
        transform: translateY(15px);
    } 100% {
        transform: translateY(0px);
    }
}

@keyframes expand {  // increases and decreases the size of an element
    0% {
        width: 60px;
        height: 60px;
    } 25% {
        width: 50px;
        height: 50px;
    } 50% {
        width: 40px;
        height: 40px;
    } 75% {
        width: 30px;
        height: 30px;
    } 88% {
        width: 20px;
        height: 20px;
    } 100% {
        width: 10px;
        height: 10px;
    }
}

@keyframes toggle-bg-color-in {   // changes the background-clor of an element
    50% { 
        opacity: 1; 
        background: rgb(214, 26, 104);
    } 50.001% { 
        opacity: 0.4;
        background: tomato;
    } 52.999% {
        opacity: 0.4; 
        background: yellow;
    } 53% {
        opacity: 1;
        background: rgb(214, 26, 104);
    }
}

@keyframes rotate-in {   // rotates an element in 360 degress
    from {
        transform: rotate(0deg);
    } to {
        transform: rotate(359deg);
    }
}

@keyframes move-clockwise-in {   // moves any element that it is applied on in a clockwise direction
    0% {
        transform: translateX(200px);
    } 25% {
        transform: translateY(120px);
    } 50% {
        transform: translateX(-200px);
    } 75% {
        transform: translateY(-200px)
    } 100% {
        transform: translateX(200px);
    }
}

The keyframes above are what we would now link or should I say chain together to give us the desired results we want. Let's look at how we can make oscillation animation work below.

.ball {
    width: 30px;
    height: 30px;
    background: #0a8754;
    border-radius: 50%;
    animation: oscillate .8s 10s ease-in infinite;
}

.zero {
   animation-delay: .2s;
}

.one {
    animation-delay: .4s;
}

.two {
    animation-delay: .6s;
}

Remember how we gave each div a unique class name, asides the generic ball class name. that's what would be used to give the element that "oscillation" feel. By setting the animation delays of each to be greater than the other, so the first div moves up and down before the second, on and on like that.

Now let's get to the main reason why we're here, chaining these animations. TO chain animations, all you have to do is separate the keyframes that we already defined with commas.

element {
     animation: oscillate .8s 10s ease-in infinite, 
               expand 2s 4s ease-in infinite,
               move-clockwise-in 3s ease-in,
               toggle-bg-color-in 11s ease-in;
}

Looking at the example above, you may have to specify a delay before each animation occurs. In the example above I used the shorthand method of specifying the animation property. Here's how it would look like if I were to use the normal method. (taking the first keyframe alone)

element {
   animation-name: oscillate;
   animation-duration: .8s;
   animation-delay: 10s;
   animation-timing-function: ease-in;
   animation-duration: infinite;
}

Now let's put the styles together.

body {
  background: #f7f0f5;
  overflow-x: hidden;
  overflow-y: hidden;
}

.flex {
    display: flex;
}

.ball {
    width: 30px;
    height: 30px;
    background: #0a8754;
    border-radius: 50%;
    animation: oscillate .8s 10s ease-in infinite, 
               expand 2s 4s ease-in infinite,
               move-clockwise-in 3s ease-in,
               toggle-bg-color-in 11s ease-in;
    overflow-x: hidden;
}

.balls {
    display: flex;
    justify-content: center;
    margin-top: 2.5%;
    animation: rotate-in 2s ease-in forwards;
    opacity: 0;
    margin-left: -8%;
    margin-top: 30%;
}

.zero {
   animation-delay: .2s;
}

.one {
    animation-delay: .4s;
}

.two {
    animation-delay: .6s;
}

.balls > div {
    margin: .3em .4em;
}
@keyframes oscillate {
    0% {
        transform: translateY(0px);
    } 50% {
        transform: translateY(15px);
    } 100% {
        transform: translateY(0px);
    }
}

@keyframes toggle-bg-color-in {
    50% { 
        opacity: 1; 
        background: rgb(214, 26, 104);
    } 50.001% { 
        opacity: 0.4;
        background: tomato;
    } 52.999% {
        opacity: 0.4; 
        background: yellow;
    } 53% {
        opacity: 1;
        background: rgb(214, 26, 104);
    }
}

@keyframes rotate-in {
    from {
        transform: rotate(0deg);
    } to {
        transform: rotate(359deg);
    }
}


@keyframes move-clockwise-in {
    0% {
        transform: translateX(200px);
    } 25% {
        transform: translateY(120px);
    } 50% {
        transform: translateX(-200px);
    } 75% {
        transform: translateY(-200px)
    } 100% {
        transform: translateX(200px);
    }
}

@keyframes expand {
    0% {
        width: 60px;
        height: 60px;
    } 25% {
        width: 50px;
        height: 50px;
    } 50% {
        width: 40px;
        height: 40px;
    } 75% {
        width: 30px;
        height: 30px;
    } 88% {
        width: 20px;
        height: 20px;
    } 100% {
        width: 10px;
        height: 10px;
    }
}

And that's how you chain animations in CSS. You can check quickly the outcome of this article on my codepen if you don't want to bother typing the code in your editor.

I hope this has helped you understand how to link(animations) together, go ahead, try out cool stuff with it.

Thanks for reading. :)