Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Infinite fade lines with reverse direction

I have three spans with border at the bottom and need it fade in and fade out from top to bottom and reverse direction. It working fine if I have 2 iterations count but with infinite not working properly.

.line {
  border-bottom: 0.2em solid #333;
  display: block;
  margin: 0 auto;
  margin-top: 0.3em;
  width: 1.5em;
}
.lines span[class='line']:nth-child(1) {
  animation: 1.5s ease-in-out 0.2s 2 alternate fade_line;
}
.lines span[class='line']:nth-child(2) {
  animation: 1s ease-in-out 0.7s 2 alternate fade_line;
}
.line {
  animation: 0.5s ease-in-out 1.2s 2 alternate fade_line;
}
@keyframes fade_line {
  0%, 50% {
    border-bottom: 0.2em solid #333;
  }
  50%,
  100% {
    border-bottom: 0.2em solid #ddd;
  }
}
<div class="lines">
  <span class="line"></span>
  <span class="line"></span>
  <span class="line"></span>
</div>

Fiddle Demo

like image 402
DimmuBoy Avatar asked Dec 28 '25 18:12

DimmuBoy


1 Answers

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>
like image 164
Harry Avatar answered Dec 31 '25 09:12

Harry



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!