[css] 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?

This question is related to css css-animations

The answer is


Delay is possible only once at the beginning with infinite. in sort delay doesn't work with infinite loop. for that you have to keep keyframes animation blanks example:

@-webkit-keyframes barshine {
  10% {background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#1e5799), color-stop(100%,#7db9e8));
    }
  60% {background: -webkit-linear-gradient(top, #7db9e8 0%,#d32a2d 100%);}
}

it will animate 10% to 60% and wait to complete 40% more. So 40% comes in delay.

find fiddle example


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;
}

Another way you can achieve a pause between animations is to apply a second animation that hides the element for the amount of delay you want. This has the benefit of allowing you to use a CSS easing function like you would normally.

.star {
  animation: shooting-star 1000ms ease-in-out infinite,
    delay-animation 2000ms linear infinite;
}

@keyframes shooting-star {
  0% {
    transform: translate(0, 0) rotate(45deg);
  }

  100% {
    transform: translate(300px, 300px) rotate(45deg);
  }
}

@keyframes delay-animation {
  0% {
    opacity: 1;
  }
  50% {
    opacity: 1;
  }
  50.01% {
    opacity: 0;
  }
  100% {
    opacity: 0;
  }
}

This only works if you want the delay to be a multiple of the animation duration. I used this to make a shower of shooting stars appear more random: https://codepen.io/ericdjohnson/pen/GRpOgVO


for a border flash: actually very simple: replace from to to 99% black and e.g 1% the shift to blue you can even make it shorter, animation time set to e.g 5sec.

@keyframes myborder {
  0% {border-color: black;}
  99% {border-color:black;}
  100% {border-color: blue;}
 }

I made a poster on the wall which moves left and right with intervals. For me it works:

.div-animation {
   -webkit-animation: bounce 2000ms ease-out;
    -moz-animation: bounce 2000ms ease-out;
    -o-animation: bounce 2000ms ease-out;
    animation: bounce 2000ms ease-out infinite;
    -webkit-animation-delay: 2s; /* Chrome, Safari, Opera */
    animation-delay: 2s;
    transform-origin: 55% 10%;    
}

@-webkit-keyframes bounce {
    0% {
        transform: rotate(0deg);
    }
    3% {
        transform: rotate(1deg);
    }
    6% {
        transform: rotate(2deg);
    }
    9% {
        transform: rotate(3deg);
    }
    12% {
        transform: rotate(2deg);
    }
    15% {
        transform: rotate(1deg);
    }
    18% {
        transform: rotate(0deg);
    }
    21% {
        transform: rotate(-1deg);
    }
    24% {
        transform: rotate(-2deg);
    }
    27% {
        transform: rotate(-3deg);
    }
    30% {
        transform: rotate(-2deg);
    }
    33% {
        transform: rotate(-1deg);
    }
    36% {
        transform: rotate(0deg);
    }
    100% {
        transform: rotate(0deg);
    }
}

Heres a little snippet that shows the same thing for 75% of the time, then it slides. This repeat schema emulates delay nicely:

@-webkit-keyframes slide    {
0%   {background-position: 0 0;}
25%  {background-position: 0 0;}
50%  {background-position: 0 0;}
75%  {background-position: 0 0;}
100% {background-position: 13em 0;}
}

@-moz-keyframes slide       {
0%   {background-position: 0 0;}
25%  {background-position: 0 0;}
50%  {background-position: 0 0;}
75%  {background-position: 0 0;}
100% {background-position: 13em 0;}
}

@keyframes slide            {
0%   {background-position: 0 0;}
25%  {background-position: 0 0;}
50%  {background-position: 0 0;}
75%  {background-position: 0 0;}
100% {background-position: 13em 0;}
}

I know this is old but I was looking for the answer in this post and with jquery you can do it easily and without too much hassle. Just declare your animation keyframe in the css and set the class with the atributes you would like. I my case I used the tada animation from css animate:

.tada {
    -webkit-animation-name: tada;
    animation-name: tada;
    -webkit-animation-duration: 1.25s;
    animation-duration: 1.25s;
    -webkit-animation-fill-mode: both;
    animation-fill-mode: both;
}

I wanted the animation to run every 10 seconds so jquery just adds the class, after 6000ms (enough time for the animation to finish) it removes the class and 4 seconds later it adds the class again and so the animation starts again.

$(document).ready(function() {
  setInterval(function() {

    $(".bottom h2").addClass("tada");//adds the class

    setTimeout(function() {//waits 6 seconds to remove the class
      $(".bottom h2").removeClass("tada");
    }, 6000);

  }, 10000)//repeats the process every 10 seconds
});

Not at all difficult like one guy posted.


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.


I would rather write a little JavaScript than make the CSS less manageable.

First, only apply the CSS animation on a data attribute change:

.progbar[data-animation="barshine"] {
    animation: barshine 1s linear;
}

Then add javascript to toggle the animation at half the delay amount.

var progbar = document.querySelector('.progbar');
var on = false;

setInterval(function () {
    progbar.setAttribute('data-animation', (on) ? 'barshine' : '');
    on = !on;
}, 3000);

Or if you don't want the animation to run when the tab is hidden:

var progbar = document.querySelector('.progbar');
var on = false;

var update = function () {
    progbar.setAttribute('data-animation', (on) ? 'barshine' : '');
    on = !on;
    setTimer();
};

var setTimer = function () {
    setTimeout(function () {
        requestAnimationFrame(update);
    }, 3000);
};

setTimer();

This is what you should do. It should work in that you have a 1 second animation, then a 4 second delay between iterations:

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

So I've been messing around with this a lot and you can do it without being very hacky. This is the simplest way to put in a delay between animation iterations that's 1. SUPER EASY and 2. just takes a little logic. Check out this dance animation I've made:

.dance{
  animation-name: dance;
  -webkit-animation-name: dance;

  animation-iteration-count: infinite;
  -webkit-animation-iteration-count: infinite;
  animation-duration: 2.5s;
  -webkit-animation-duration: 2.5s;

  -webkit-animation-delay: 2.5s;
  animation-delay: 2.5s;
  animation-timing-function: ease-in;
  -webkit-animation-timing-function: ease-in;

}
@keyframes dance {
  0% {
    -webkit-transform: rotate(0deg);
    -moz-transform: rotate(0deg);
    -o-transform: rotate(0deg);
    -ms-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  25% {
    -webkit-transform: rotate(-120deg);
    -moz-transform: rotate(-120deg);
    -o-transform: rotate(-120deg);
    -ms-transform: rotate(-120deg);
    transform: rotate(-120deg);
  }
  50% {
    -webkit-transform: rotate(20deg);
    -moz-transform: rotate(20deg);
    -o-transform: rotate(20deg);
    -ms-transform: rotate(20deg);
    transform: rotate(20deg);
  }
  100% {
    -webkit-transform: rotate(0deg);
    -moz-transform: rotate(0deg);
    -o-transform: rotate(0deg);
    -ms-transform: rotate(0deg);
    transform: rotate(0deg);
  }
}

@-webkit-keyframes dance {
  0% {
    -webkit-transform: rotate(0deg);
    -moz-transform: rotate(0deg);
    -o-transform: rotate(0deg);
    -ms-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  20% {
    -webkit-transform: rotate(20deg);
    -moz-transform: rotate(20deg);
    -o-transform: rotate(20deg);
    -ms-transform: rotate(20deg);
    transform: rotate(20deg);
  }
  40% {
    -webkit-transform: rotate(-120deg);
    -moz-transform: rotate(-120deg);
    -o-transform: rotate(-120deg);
    -ms-transform: rotate(-120deg);
    transform: rotate(-120deg);
  }
  60% {
    -webkit-transform: rotate(0deg);
    -moz-transform: rotate(0deg);
    -o-transform: rotate(0deg);
    -ms-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  80% {
    -webkit-transform: rotate(-120deg);
    -moz-transform: rotate(-120deg);
    -o-transform: rotate(-120deg);
    -ms-transform: rotate(-120deg);
    transform: rotate(-120deg);
  }
  95% {
    -webkit-transform: rotate(20deg);
    -moz-transform: rotate(20deg);
    -o-transform: rotate(20deg);
    -ms-transform: rotate(20deg);
    transform: rotate(20deg);
  }
}

I actually came here trying to figure out how to put a delay in the animation, when I realized that you just 1. extend the duration of the animation and shirt the proportion of time for each animation. Beore I had them each lasting .5 seconds for the total duration of 2.5 seconds. Now lets say i wanted to add a delay equal to the total duration, so a 2.5 second delay.

You animation time is 2.5 seconds and delay is 2.5, so you change duration to 5 seconds. However, because you doubled the total duration, you'll want to halve the animations proportion. Check the final below. This worked perfectly for me.

@-webkit-keyframes dance {
  0% {
    -webkit-transform: rotate(0deg);
    -moz-transform: rotate(0deg);
    -o-transform: rotate(0deg);
    -ms-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  10% {
    -webkit-transform: rotate(20deg);
    -moz-transform: rotate(20deg);
    -o-transform: rotate(20deg);
    -ms-transform: rotate(20deg);
    transform: rotate(20deg);
  }
  20% {
    -webkit-transform: rotate(-120deg);
    -moz-transform: rotate(-120deg);
    -o-transform: rotate(-120deg);
    -ms-transform: rotate(-120deg);
    transform: rotate(-120deg);
  }
  30% {
    -webkit-transform: rotate(0deg);
    -moz-transform: rotate(0deg);
    -o-transform: rotate(0deg);
    -ms-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  40% {
    -webkit-transform: rotate(-120deg);
    -moz-transform: rotate(-120deg);
    -o-transform: rotate(-120deg);
    -ms-transform: rotate(-120deg);
    transform: rotate(-120deg);
  }
  50% {
    -webkit-transform: rotate(0deg);
    -moz-transform: rotate(0deg);
    -o-transform: rotate(0deg);
    -ms-transform: rotate(0deg);
    transform: rotate(0deg);
  }
}

In sum:

These are the calcultions you'd probably use to figure out how to change you animation's duration and the % of each part.

desired_duration = x

desired_duration = animation_part_duration1 + animation_part_duration2 + ... (and so on)

desired_delay = y

total duration = x + y

animation_part_duration1_actual = animation_part_duration1 * desired_duration / total_duration


You can create a "fake" delay between infinite animations purely with CSS. The way to do it is smartly define your keyframe animation points and your animation duration speed.

For example, if we wanted to animate a bouncing ball, and we wanted a good .5s to 1s delay between each bounce, we can do something like:

@keyframes bounce{
    0%{
        transform: translateY(0);
    }
    50%{
        transform: translateY(25%);
    }
    75%{
        transform: translateY(15%);
    }
    90%{
        transform: translateY(0%);
    }
    100%{
        transform: translateY(0);
    }
}

What we do is make sure that the ball goes back to its original position much earlier than 100%. In my example, I'm doing it in 90% which provided me with around .1s delay which was good enough for me. But obviously for your case, you can either add more key frame points and change the transform values.

Furthermore, you can add additional animation duration to balance your key frame animations.

For example:

 animation: bounce .5s ease-in-out infinite;

Lets say that we wanted the full animation to end in .5s, but we wanted an additional .2s in delay between the animations.

 animation: bounce .7s ease-in-out infinite;

So we'll add an additional .2s delay, and in our key frame animations, we can add more percentage points to fill in the gaps of the .2s delay.