93

I am trying to create a cascading effect by applying an animation to each child element. I was wondering if there is a better way to do it than this:

.myClass img:nth-child(1){
    -webkit-animation: myAnimation 0.9s linear forwards;
}
.myClass img:nth-child(2){
    -webkit-animation: myAnimation 0.9s linear 0.1s forwards;
}
.myClass img:nth-child(3){
    -webkit-animation: myAnimation 0.9s linear 0.2s forwards;
}
.myClass img:nth-child(4){
    -webkit-animation: myAnimation 0.9s linear 0.3s forwards;
}
.myClass img:nth-child(5){
    -webkit-animation: myAnimation 0.9s linear 0.4s forwards;
}

and so on... So basically, I'd like to have an animation starting for each child but with a delay. Thanks for any input!

Addition: Maybe I did not properly explain what was my concern: It's about how to do this no matter how many children I have. How to do this without having to write down the properties for every child... for example, when I don't know how many children there are going to be.

Seka
  • 1,413
  • 2
  • 12
  • 16
  • what about using some js element selector(something like dojo.query or jquery) and apply style in for loop? thats only thing that comes to my mind... – Gatekeeper Nov 28 '11 at 10:28
  • Yes, I guess that's the only way to do it for each child without having to write down a class for each one. I thought that there might be some new CSS3 properties that make it possible but I guess I'll have to wait for the introduction of variables... Thanks! – Seka Nov 28 '11 at 10:42
  • 4
    So you're after some kind of [increment property](http://www.w3schools.com/cssref/pr_gen_counter-increment.asp) for CSS animations? Something like `-webkit-animation-increment`? That would definitely be of use, good question. – CherryFlavourPez Nov 28 '11 at 12:13
  • @Ed-M exactly! I was just looking at that counter-increment property and it would be so great if some variable like that could be used in any css property definition and not just the 'content' one... – Seka Nov 28 '11 at 12:37

7 Answers7

81

Here's a scss way to do it using a for loop.

@for $i from 1 through 10 {
    .myClass img:nth-child(#{$i}n) {
        animation-delay: #{$i * 0.5}s;
    }
}
robshearing
  • 1,034
  • 8
  • 6
77

What you want is the animation delay property.

@keyframes FadeIn { 
  0% {
    opacity: 0;
    transform: scale(.1);
  }

  85% {
    opacity: 1;
    transform: scale(1.05);
  }
  100% {
    transform: scale(1);
  }
}

.myClass img {
  float: left;
  margin: 20px;
  animation: FadeIn 1s linear;
  animation-fill-mode: both;
}

.myClass img:nth-child(1) { animation-delay: .5s }
.myClass img:nth-child(2) { animation-delay: 1s }
.myClass img:nth-child(3) { animation-delay: 1.5s }
.myClass img:nth-child(4) { animation-delay: 2s }
<div class="myClass">
    <img src="http://placehold.it/200x150" />
    <img src="http://placehold.it/200x150" />
    <img src="http://placehold.it/200x150" />
    <img src="http://placehold.it/200x150" />
</div>

A CSS preprocessor such as Less.js or Sass can reduce the amount of repetition, but if you're working with an unknown number of child elements or need to animate a large number then JavaScript will be the best option.

CherryFlavourPez
  • 7,529
  • 5
  • 45
  • 47
  • @dreamster: the old Fiddle uses the `-webkit` prefix (which is still supported in Chrome). You'll want to add in the non-prefixed version (or use something like autoprexfixer (https://github.com/postcss/autoprefixer) if you want this to work. – CherryFlavourPez Jan 06 '16 at 11:33
35

In the [hopefully near] future when attr and calc are fully supported, we'll be able to accomplish this without JavaScript.

HTML:

<ul class="something">
    <li data-animation-offset="1.0">asdf</li>
    <li data-animation-offset="1.3">asdf</li>
    <li data-animation-offset="1.1">asdf</li>
    <li data-animation-offset="1.2">asdf</li>
</ul>

CSS:

.something > li
{
    animation: myAnimation 1s ease calc(0.5s * attr(data-animation-offset number 1));
}

This would create an effect where each list item animates in what would appear to be random order.

Steven Vachon
  • 3,814
  • 1
  • 30
  • 30
  • 32
    TBH i expected Something like `.myClass li:nth-child(n) { transition-delay: calc(n*0.2s); }` this would come extremely handy. – Felype Apr 27 '15 at 23:01
  • 1
    I meant to say I hoped w3 could implement in a future nth-child functions with variables so we could for example say `transition-delay` for child(n) is `0.5+(n* % 1.5)` its not a marvelous formula but would look random for whatever number of li's you'd possibly add. My complaint is on having to create several CSS selections for each list items and then having to expand it whenever I get a list larger than my CSS is prepared for, there are functions for random on SCSS and LESS, but goes much offtopic on question, so my frustration can't be helped with plain CSS. – Felype May 01 '15 at 05:11
  • My point is: CSS should cover all visuals, that's what it's posed for, but sometimes we can't help the need to use JS to achieve the graphical result we intend. And yeah that looks random, but after running that animation several times your eyes will start to predict it and it wont look random anymore. – Felype May 01 '15 at 05:12
  • The user probably wouldn't notice. It's like movie bloopers -- very few notice them. The pseudo-randomness is *felt* though. – Steven Vachon May 07 '15 at 23:41
  • One day, we will be able to write `counter-increment: animation-offset; animation-delay: calc(0.1s * counter-value(animation-offset));` but the world is not yet ready for this – jsan Sep 25 '21 at 16:45
22

You can also make use of the transition-delay property in CSS and use JS or JQuery to assign a different delay for each child element . ( Assume s to be the starting delay in seconds )

$(".myClass img").each(function(index){
     $(this).css({
          'transition-delay' : s*(1+index) + 's'
     });
 });

So, the children will have the transition delays like 1*s, 2*s, 3*s ..... and so on. Now to create the actual animation effect simply set the required transition and the children will be animated in a sequence. Works like a charm !

Adk96r
  • 219
  • 3
  • 5
  • I think performance-wise this is the best solution on this page because it still lets the animation itself be fully done through css. Also, it prevents file bloating and unneccesary illegibility. – eleven59 Oct 19 '17 at 14:08
10

If you have a lot of items (for example: I have paginated table with >1000 items and wanna each row to be animated with delay when page is loads), you can use jQuery to solve this and avoid css file rising in size. Animation delay dynamically increases.

$.each($('.myClass'), function(i, el){
    $(el).css({'opacity':0});
    setTimeout(function(){
       $(el).animate({
        'opacity':1.0
       }, 450);
    },500 + ( i * 500 ));

});​

EDIT: Here is the same code I adjusted to use with animate.css (install additional plugin before use https://gist.github.com/1438179 )

$.each($(".myClass"), function(i, el){
    $(el).css("opacity","0");
    setTimeout(function(){
       $(el).animateCSS("fadeIn","400");
    },500 + ( i * 500 ));

});

Where "fadeIn" is animation type, "400" - animation execute time, 500 - delay for each element on page to be animated.

Neolo
  • 127
  • 1
  • 7
  • 4
    I think this answer goes against the spirit of what was being asked, namely a way to do it via CSS animation versus JavaScript/jQuery animation. – Sean Ouimet Nov 12 '13 at 23:12
5

Like this:

.myClass img {
    -webkit-animation: myAnimation 0.9s linear forwards;
}

.myClass img:nth-child(1){
    -webkit-animation-delay: 0.1s;
}

.myClass img:nth-child(2){
    -webkit-animation-delay: 0.2s;
}

[...etc...]
peduarte
  • 1,667
  • 3
  • 16
  • 24
  • 1
    Hi, thanks for the simplification :) I was actually more concerned about the ongoing cascade of adding 0.1 seconds of delay and not simplifying the classes itself. But of course, that's a better way to write it down, thanks! – Seka Nov 28 '11 at 10:41
  • Oh, ok, my bad. Well, you could do it with Javascript, doing a for each loop. But I wouldn't recommend it... – peduarte Nov 28 '11 at 10:42
0

I'm leaving this here in case someone using reactJS needs it, just like I did:

index.css file:

.scale-in-center {
  -webkit-animation: scale-in-center 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
  animation: scale-in-center 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
}

.animationClass {
  animation: scale-in-center 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
}

map render function inside JS file:

{YourArrayOfItemsHere.map((item, index) => (
  <div style={{animationDelay: index / 25 + "s"}} className="animationClass">
    <b>{item['name']}</b>
  </div>
))}

The style={{animationDelay: index / 25 + "s"}} style makes so each item has its own delay. You can adjust it by changing the calculation.