Data Mastery
Data Mastery

Reputation: 2085

Animate one div after another with pure css

<style>
@keyframes bounceIn {
  from,
  20%,
  40%,
  60%,
  80%,
  to {
    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
  }

  0% {
    opacity: 0;
    -webkit-transform: scale3d(0.3, 0.3, 0.3);
    transform: scale3d(0.3, 0.3, 0.3);
  }

  20% {
    -webkit-transform: scale3d(1.1, 1.1, 1.1);
    transform: scale3d(1.1, 1.1, 1.1);
  }

  40% {
    -webkit-transform: scale3d(0.9, 0.9, 0.9);
    transform: scale3d(0.9, 0.9, 0.9);
  }

  60% {
    opacity: 1;
    -webkit-transform: scale3d(1.03, 1.03, 1.03);
    transform: scale3d(1.03, 1.03, 1.03);
  }

  80% {
    -webkit-transform: scale3d(0.97, 0.97, 0.97);
    transform: scale3d(0.97, 0.97, 0.97);
  }

  to {
    opacity: 1;
    -webkit-transform: scale3d(1, 1, 1);
    transform: scale3d(1, 1, 1);
  }
}

.card {
  height: 400px;
  width: 100%;
  max-width: 360px;
  margin: 50px 10px 0px 10px;
  box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
  transition: all 0.3s cubic-bezier(.25,.8,.25,1);
  animation: bounceIn 0.85s linear forwards;
}

I use the code from animated.css to animate my card. I have multiple cards which I would like to animate one after another. Delay for first card would be 0.85s, 0.9s for the seconds, 0.95s for the third and so on. Is there a way to do this in CSS without creating a ton of new classes like an .card_1, .card_2 and so on?

Upvotes: 4

Views: 2251

Answers (3)

Jeff Hernandez
Jeff Hernandez

Reputation: 405

I don't think you can do this with pure css without writing out each id or class and changing the animation css property to include .05 more seconds.

You could do this programmatically with javascript.

const beginSpeed = 0.85
const cards = []

cards.forEach((card, i) => {
  cards.push(<div id=`card_${i}` class="card" style=`animation: bounceIn ${beginSpeed + (i * .05)}s linear forwards;` ></div>)
})

Alternatively if you just want to use a for loop

const beginSpeed = 0.85
const numberOfCardsDesired = 40
const cards = []

for(let i = 0; i < numberOfCardsDesired; i++) {
  cards.push(<div id=`card_${i}` class="card" style=`animation: bounceIn ${beginSpeed + (i * .05)}s linear forwards;` ></div>)
}

By multiplying .05 time the index it would cause each subsequent div element to by .05 seconds after the previous one. In your css, you can include the card with all the static css elements. By doing this, you could just change the variable "numberOfCardsDesired" to whatever number you want and that many cards would animate

.card {
  height: 400px;
  width: 100%;
  max-width: 360px;
  margin: 50px 10px 0px 10px;
  box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
}

I apologize if my answer wasn't exactly what you're looking for as it's not strictly using CSS. Hopefully this helped you in some way. Good luck!

Upvotes: 0

MrBizle
MrBizle

Reputation: 418

No, without doing something really funky like this your .css file has no way of knowing how many elements you have to animate. Depending on your environment i'd either recommended using an inline style for transition duration rendered with server-side logic if possible, or using JavaScript if not.

Server-side example with Twig templates:

{% for item in items %} 
    <div class="card" style="transition-duration={{ loop.index }}s"></div> 
{% endfor %}

Example in Javascript:

[...document.querySelectorAll('.card')].forEach((card, i) => {
    card.style.transitionDuration = i + 's'
})

I haven't worked out the exact delays requested, or tested the above. But this is the approach.

Upvotes: 0

chriskirknielsen
chriskirknielsen

Reputation: 2929

It looks like you are after a stagger animation. Here are two methods of doing this:

Sass Loop

This is the most "costly" in terms of final CSS code, and requires pre-processing. If you don't have too many items, it remains pretty acceptable, and will work on more browsers, if you have to target older ones.

/* Your previous styles… */
.card {
  $initial-delay: .85s;
  $increase-delay: .1s;
  $total-cards: 10; /* Say you have 10 cards, you can change this number */
  
  @for $i from 1 through $total-cards {
    &:nth-child($i) {
      $zero-i: $i - 1; // Make it zero-based
      animation-delay: #{ $initial-delay + $zero-i * $increase-delay };  
    }
  }
}

CSS custom properties

Modern browsers can use css custom properties, also known as CSS variables. By assigning the same values from the Sass example into your markup, you can reach the same result.

<ul class="card-container" style="--t: 10;">
   <li class="card" style="--i: 0;">Card content…</li>
   <li class="card" style="--i: 1;">Card content…</li>
   <li class="card" style="--i: 2;">Card content…</li>
   <!-- And so on… -->
</ul>
/* Your previous styles… */
.card {
  animation-delay: calc(.85s + .1s * var(--i));
}

Less CSS but you will probably need to process your HTML output to append these additional style attributes on each item. Note that the container's assignment of --t is not required here, but I wanted to make sure you could see how each method works.

Upvotes: 4

Related Questions