The problem with the animation is that the animation-delay
actually applies only to the first iteration of an animation. The below is an explanation of why it works when there are only 2 iterations and why it doesn't when there are infinite iterations.
Why does it work when there are only 2 iterations?
- First
span
starts its animation at 0.2s
(after animation-delay
). Between 0.2s
to 1.7s
, the border color goes from #333
to #ddd
(at 0.95s
which is 50%
of 1.5s
duration to be precise) and between 1.7s
and 3.2s
it goes back (reverse direction) from #ddd
to #333
(at 2.45s
to be precise).
- Second
span
starts its animation at 0.7s
. Between 0.7s
to 1.7s
, the border color goes from #333
to #ddd
(at 1.2s
to be precise) and between 1.7s
to 2.7s
it goes back (reverse) from #ddd
to #333
(at 2.2s
to be precise).
- Third
span
starts its animation at 1.2s
. Between 1.2s
to 1.7s
, the border color goes from #333
to #ddd
(at 1.45s
to be precise) and between 1.7s
to 2.2s
it goes back (reverse) from #ddd
to #333
(at 1.95s
to be precise).
Element | Iteration 1 | Iteration 2
---------------------------------------------------
First Span | 0.95s | 2.45s
Second Span | 1.2s | 2.2s
Third Span | 1.45s | 1.95s
As you can see, there is a nice flow to it as far as there are only 2 iterations.
Why does it not work when the iteration count is set to infinite?
Now lets see what happens with the third and subsequent iterations:
- First
span
- Between 3.2s
to 4.7s
, the border color goes from #333
to #ddd
(at 3.95s
to be precise) and between 4.7s
and 6.2s
it goes back (reverse) from #ddd
to #333
(at 5.45s
to be precise).
- Second
span
- Between 2.7s
to 3.7s
the border color goes from #333
to #ddd
(at 3.2s
to be precise) and between 3.7s
to 4.7s
it goes back (reverse) from #ddd
to #333
(at 4.2s
to be precise).
- Third
span
- Between 2.2s
to 2.7s
the border color goes from #333
to #ddd
(at 2.45s
to be precise) and between 2.7s
to 3.2s
it goes back (reverse) from #ddd
to #333
(at 2.95s
to be precise).
Element | Iteration 1 | Iteration 2 | Iteration 3 | Iteration 4
------------------------------------------------------------------------------------------
First Span | 0.95s | 2.45s | 3.95s | 5.45s
Second Span | 1.2s | 2.2s | 3.2s | 4.2s
Third Span | 1.45s | 1.95s | 2.45s | 2.95s
As you can see the flow is completely messed up because the animations start to overlap due to the way the animation duration and delay are configured.
Solutions:
Generally, the approach for introducing a delay between each iteration of an infinite loop animation is to modify the keyframes such that they add an equal delay for every iteration. I had explained this in my answer here. Unfortunately, your case is a lot more complex due to reverse animation. I couldn't modify the keyframes to match your expectation but I hope you'd find the abov explanation helpful in understanding the issue.
If you are happy to use alternate methods to achieve the same effect then you could have a look at linear-gradient
background images to create the hamburger effect and then add animation to it.
.lines {
margin: 0 auto;
height: 30px;
width: 30px;
background-image: linear-gradient(#333, #333), linear-gradient(#333, #333), linear-gradient(#333, #333);
background-size: 100% 5px;
background-position: 0px 5px, 0px 15px, 0px 25px;
background-repeat: no-repeat;
animation: bars 1.7s infinite alternate ease-in-out;
}
@keyframes bars {
0% {
background-image: linear-gradient(#333, #333), linear-gradient(#333, #333), linear-gradient(#333, #333);
}
33% {
background-image: linear-gradient(#ddd, #ddd), linear-gradient(#333, #333), linear-gradient(#333, #333);
}
66% {
background-image: linear-gradient(#ddd, #ddd), linear-gradient(#ddd, #ddd), linear-gradient(#333, #333);
}
100% {
background-image: linear-gradient(#ddd, #ddd), linear-gradient(#ddd, #ddd), linear-gradient(#ddd, #ddd);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class="lines"></div>
Below is a solution using your initial approach (kindly contributed by vals). But you can't reuse the keyframes!
.line {
border-bottom: 0.2em solid #333;
display: block;
margin: 0 auto;
margin-top: 0.3em;
width: 1.5em;
}
.line {
animation: 1.7s ease-in-out infinite alternate fade_line1;
}
.line:nth-child(2) {
animation-name: fade_line2;
}
.line:nth-child(3) {
animation-name: fade_line3;
}
@keyframes fade_line1 { /* use 25% instead of 30% if the splits need to be equal among all 3 */
0%, 30% {
border-bottom-color: #333;
}
30%, 100% {
border-bottom-color: #ddd;
}
}
@keyframes fade_line2 {
0%, 50% {
border-bottom-color: #333;
}
50%, 100% {
border-bottom-color: #ddd;
}
}
@keyframes fade_line3 { /* use 75% instead of 70% if the splits need to be equal among all 3 */
0%, 70% {
border-bottom-color: #333;
}
70%, 100% {
border-bottom-color: #ddd;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class="lines">
<span class="line"></span>
<span class="line"></span>
<span class="line"></span>
</div>