I usually use JavaScript to animate items on webpage sequentially. Recently, I have understood that I can use CSS3 keyframes to animate items sequentially. To demonstrate that, I animate bars (increasing width from left to right) sequentially here.
So, my HTML structure looks like this; Each bar is represented here in a div HTML element with a class bar.
<div class="bar-container">
<div class="bar bar_0">
</div>
<div class="bar bar_1">
</div>
<div class="bar bar_2">
</div>
<div class="bar bar_3">
</div>
<div class="bar bar_4">
</div>
<div class="bar bar_5">
</div>
</div>
The bars are animated one after the other; the bars of different width and their actual bar animation duration depends on their width. I use SASS for this example.
I first set the width and height of the bar and their background as you can see below.
.bar {
width: 100px;
height: 50px;
background-color: rgba(66, 237, 148, 0.6);
}
Now I set specific width to each bar using their unique CSS classname. As you can see each bars set different width and &.bar_5 is not defined styles because I want it to inherit width property from the common class .bar and other properties will be set later. I have used percentage value for the bar which is related to browser window width.
.bar {
width: 100px;
height: 50px;
background-color: rgba(66, 237, 148, 0.6);
&.bar_0 {
width: 30%;
}
&.bar_1 {
width: 50%;
}
&.bar_2 {
width: 60%;
}
&.bar_3 {
width: 70%;
}
&.bar_4 {
width: 75%;
}
}
The above HTML and CSS together will render as.
Now the most interesting part, Animation. Since there are 6 bars we will have to have six different @keyframes to animate them sequentially. Let me show the @keyframes first then I explain them in details.
$percentages: (30, 50, 60, 65, 75, 100);
$factor: 20;
$interval: 0.5;
$previousAnimation: 0;
@for $i from 1 through 6 {
@keyframes bar_animate_#{$i - 1} {
@if $i > 2
{
$previousAnimation: $previousAnimation + ($factor * nth($percentages, $i - 1) / 100) + $interval;
0%, #{($previousAnimation)}% {
transform: scaleX(0);
transform-origin: left;
}
}
@else if $i == 2{
$previousAnimation: $previousAnimation + ($factor * nth($percentages, $i - 1) / 100) + $interval;
0%, #{$previousAnimation }%
{
transform: scaleX(0);
transform-origin: left;
}
}
@else
{
0%
{
transform: scaleX(0);
transform-origin: left;
}
}
#{$previousAnimation + ($factor * nth($percentages, $i) / 100)}%, 100%
{
transform: scaleX(1);
transform-origin: left;
}
}
}
Basically, I animate from scaleX(0) to scaleX(1) with transform-origin. The reason to have transform-origin is to tell transform property to start the scaling from left rather than from center (by default).
The important part is animation starting timing; it is represented here in %(percentage). Let's add animation to bar elements.
.bar {
width: 100px;
height: 50px;
background-color: rgba(66, 237, 148, 0.6);
animation-duration: 10s; //Added now
&.bar_0 {
width: 30%;
animation-name: bar_animate_0; //Added now
}
&.bar_1 {
width: 50%;
animation-name: bar_animate_1; //Added now
}
&.bar_2 {
width: 60%;
animation-name: bar_animate_2; //Added now
}
&.bar_3 {
width: 70%;
animation-name: bar_animate_3; //Added now
}
&.bar_4 {
width: 75%;
animation-name: bar_animate_4; //Added now
}
&.bar_5{
animation-name: bar_animate_5; //Added now
}
}
I have added animation-duration and animation-name; the overall animation duration is same for all element but actual bar animation duration and start timing are different. If you look closely I animate bar_0 from 0s to 0.6s (0% to 6% of 10s) and rest of the animation duration stays the same and also during this time, all other bars do not animate because they are set to transform: scaleX(0) which basically set width to 0 (hidden). Then, I give .5s (.5%) duration for next bar element to start animation then next bar animate for 1s and so the same logic goes till the last bar element.
This is how I was able to animate the elements sequentially with just CSS3 @keyframes.
If you have any questions or suggestions please write below. Thanks
Top comments (3)
Pretty cool!
There's also
animation-delay
, which is helpful for spacing out the timing of animations: developer.mozilla.org/en-US/docs/W...Side note: one reason why I like preprocessors (my go to is Sass) is that necessarily repetitive CSS can be encapsulated in a
for
loop:And similarly for the
.bar_[i]
classes.One more thing, looks like the CSS in that last block is correct, you set all the animations to
bar_animate_5
. The Codepen is correct though.Thanks for suggesting improvement and pointing out the mistake. I have corrected the mistake now. I will refactor it in the evening.
@Steven, I have refactored the animation to use Sass's for loop and updated the article. Many thanks for suggesting the improvement.