CSS animation delay in repeating

I've recently discovered how to "properly" use CSS animations (previously I dismissed them as not being able to make complex sequences like you could in JavaScript). So now I'm learning about them.

For this effect, I'm trying to have a gradient "flare" sweep across a progress bar-like element. Similar to the effect on native Windows Vista/7 progress bars.

@keyframes barshine {
  from {background-image:linear-gradient(120deg,rgba(255,255,255,0) -10%,rgba(255,255,255,0.25) -5%,rgba(255,255,255,0) 0%);}
  to {background-image:linear-gradient(120deg,rgba(255,255,255,0) 100%,rgba(255,255,255,0.25) 105%,rgba(255,255,255,0) 110%);}
}
.progbar {
  animation: barshine 1s 4s linear infinite;
}

As you can see, I am trying to have a delay of 4 seconds, followed by the shine sweeping across in 1 second, repeated.

However, it seems that the animation-delay only applies to the first iteration, after which the shine just keeps sweeping across repeatedly.

I "resolved" this issue as follows:

@keyframes expbarshine {
  from {background-image:linear-gradient(120deg,rgba(255,255,255,0) -10%,rgba(255,255,255,0.25) -5%,rgba(255,255,255,0) 0%);}
  80% {background-image:linear-gradient(120deg,rgba(255,255,255,0) -10%,rgba(255,255,255,0.25) -5%,rgba(255,255,255,0) 0%);}
  to {background-image:linear-gradient(120deg,rgba(255,255,255,0) 100%,rgba(255,255,255,0.25) 105%,rgba(255,255,255,0) 110%);}
}
.progbar {
  animation: barshine 5s linear infinite;
}

from and 80% are exactly the same, resulting in a "delay" of 80% of the animation length.

This works, but for my next animation, I need the delay to be variable (constant for a particular element, but variable among elements that use the animation), while the animation itself stays exactly the same length.

With the above "solution", I would end up with a slower animation when all I want is a longer delay.

Is it possible to have the animation-delay apply to all iterations, rather than just the first?


Solution 1:

I had a similar problem and used

@-webkit-keyframes pan {
   0%, 10%       { -webkit-transform: translate3d( 0%, 0px, 0px); }
   90%, 100%     { -webkit-transform: translate3d(-50%, 0px, 0px); }
}

Bit irritating that you have to fake your duration to account for 'delays' at either end.

Solution 2:

minitech is right in that animation-delay specifies the delay before the animation starts and NOT the delay in between iterations. The editors draft of the spec describes it well and there was a discussion of this feature you're describing here which suggesting this iteration delay feature.

While there may be a workaround in JS, you can fake this iteration delay for the progress bar flare using only CSS.

By declaring the flare div position:absolute and the parent div overflow: hidden, setting the 100% keyframe state greater than the width of the progress bar, and playing around with the cubic-bezier timing function and left offset values, you're able to emulate an ease-in-out or linear timing with a "delay".

It'd be interesting to write a less/scss mixin to calculate exactly the left offset and timing function to get this exact, but I don't have the time at the moment to fiddle with it. Would love to see something like that though!

Here's a demo I threw together to show this off. (I tried to emulate the windows 7 progress bar and fell a bit short, but it demonstrates what I'm talking about)

Demo: http://codepen.io/timothyasp/full/HlzGu

<!-- HTML -->
<div class="bar">
   <div class="progress">
      <div class="flare"></div>
   </div>
</div>


/* CSS */

@keyframes progress {
  from {
    width: 0px;
  }
  to {
    width: 600px;
  }
}

@keyframes barshine {
  0% {
    left: -100px;
  }

  100% {
    left: 1000px;
  }
}
.flare {
  animation-name: barshine;
  animation-duration: 3s;
  animation-direction: normal;
  animation-fill-mode: forwards;
  animation-timing-function: cubic-bezier(.14, .75, .2, 1.01);
  animation-iteration-count: infinite;
  left: 0;
  top: 0;
  height: 40px;
  width: 100px;
  position: absolute;
  background: -moz-radial-gradient(center, ellipse cover,  rgba(255,255,255,0.69) 0%, rgba(255,255,255,0) 87%); /* FF3.6+ */
  background: -webkit-gradient(radial, center center, 0px, center center, 100%, color-stop(0%,rgba(255,255,255,0.69)), color-stop(87%,rgba(255,255,255,0))); /* Chrome,Safari4+ */
  background: -webkit-radial-gradient(center, ellipse cover,  rgba(255,255,255,0.69) 0%,rgba(255,255,255,0) 87%); /* Chrome10+,Safari5.1+ */
  background: -o-radial-gradient(center, ellipse cover,  rgba(255,255,255,0.69) 0%,rgba(255,255,255,0) 87%); /* Opera 12+ */
  background: -ms-radial-gradient(center, ellipse cover,  rgba(255,255,255,0.69) 0%,rgba(255,255,255,0) 87%); /* IE10+ */
  background: radial-gradient(ellipse at center,  rgba(255,255,255,0.69) 0%,rgba(255,255,255,0) 87%); /* W3C */
  filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#b0ffffff', endColorstr='#00ffffff',GradientType=1 ); /* IE6-9 fallback on horizontal gradient */
  z-index: 10;
}
.progress {
  animation-name: progress;
  animation-duration: 10s;
  animation-delay: 1s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
  overflow: hidden;
  position:relative;
  z-index: 1;
  height: 100%;
  width: 100%;
  border-right: 1px solid #0f9116;
  background: #caf7ce; /* Old browsers */
  background: -moz-linear-gradient(top, #caf7ce 0%, #caf7ce 18%, #3fe81e 45%, #2ab22a 96%); /* FF3.6+ */
  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#caf7ce), color-stop(18%,#caf7ce), color-stop(45%,#3fe81e), color-stop(96%,#2ab22a)); /* Chrome,Safari4+ */
  background: -webkit-linear-gradient(top, #caf7ce 0%,#caf7ce 18%,#3fe81e 45%,#2ab22a 96%); /* Chrome10+,Safari5.1+ */
  background: -o-linear-gradient(top, #caf7ce 0%,#caf7ce 18%,#3fe81e 45%,#2ab22a 96%); /* Opera 11.10+ */
  background: -ms-linear-gradient(top, #caf7ce 0%,#caf7ce 18%,#3fe81e 45%,#2ab22a 96%); /* IE10+ */
  background: linear-gradient(to bottom, #caf7ce 0%,#caf7ce 18%,#3fe81e 45%,#2ab22a 96%); /* W3C */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#caf7ce', endColorstr='#2ab22a',GradientType=0 ); /* IE6-9 */
}

.progress:after {
  content: "";
  width: 100%;
  height: 29px;
  right: 0;
  bottom: 0;
  position: absolute;
  z-index: 3;
  background: -moz-linear-gradient(left, rgba(202,247,206,0) 0%, rgba(42,178,42,1) 100%); /* FF3.6+ */
  background: -webkit-gradient(linear, left top, right top, color-stop(0%,rgba(202,247,206,0)), color-stop(100%,rgba(42,178,42,1))); /* Chrome,Safari4+ */
  background: -webkit-linear-gradient(left, rgba(202,247,206,0) 0%,rgba(42,178,42,1) 100%); /* Chrome10+,Safari5.1+ */
  background: -o-linear-gradient(left, rgba(202,247,206,0) 0%,rgba(42,178,42,1) 100%); /* Opera 11.10+ */
  background: -ms-linear-gradient(left, rgba(202,247,206,0) 0%,rgba(42,178,42,1) 100%); /* IE10+ */
  background: linear-gradient(to right, rgba(202,247,206,0) 0%,rgba(42,178,42,1) 100%); /* W3C */
  filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00caf7ce', endColorstr='#2ab22a',GradientType=1 ); /* IE6-9 */
}

.bar {
  margin-top: 30px;
  height: 40px;
  width: 600px;
  position: relative;
  border: 1px solid #777;
  border-radius: 3px;
}