Chaining Multiple CSS Animations

jdesilvio picture jdesilvio · Oct 8, 2015 · Viewed 11.1k times · Source

I am trying to chain together 2 CSS animations, see pen: http://codepen.io/jdesilvio/pen/pjwvyO

I have followed the syntax provided in other answers to similar questions, but they don't seem to work correctly:

animation-name: falling, laydown;
animation-duration: 2000ms, 1000ms;
animation-timing-function: ease-in, ease-out;
animation-iteration-count: 1, 1;

It is playing the second animation, then the first and finally the second one again. How can I get it to play the first, then second?

Here is the full code:

Answer

Harry picture Harry · Oct 8, 2015

The problem is actually not with the order of the animations but because of how multiple animations on pme element works. When multiple animations are added on an element, they start at the same time by default.

Because of this, both the laydown and falling animations start at the same time but the laydown animation actually completes within 1000ms from the start but the first animation (which is falling) doesn't complete till 2000ms.

The W3C spec about animations also say the following about multiple animations accessing the same property during animation:

If multiple animations are attempting to modify the same property, then the animation closest to the end of the list of names wins.

In the code provided in question, both animations are trying to modify the transform property and the second animation is the closest to the end. So while the second animation is still running (which is, for the first 1000ms) the transform changes are applied as specified in the second animation. During this time the first animation is still running but it has no effect because its values are overwritten. In the 2nd 1000ms (when the second animation has already completed but 1st is still executing), the transforms are applied as directed by the first animation. This is why it looks as if the second animation is running before the first animation and then the first.


To fix this problem, the execution of the second animation should be put on hold (or delayed) until the time the first animation is complete. This can be done by adding a animation-delay (that is equal to the animation-duration of the first animation) for the second animation.

animation-name: falling, laydown;
animation-duration: 2000ms, 1000ms;
animation-delay: 0ms, 2000ms; /* add this */
animation-timing-function: ease-in, ease-out;
animation-iteration-count: 1, 1;

html,
body {
  height: 100%;
}
body {
  display: flex;
  align-items: center;
  justify-content: center;
}
@keyframes falling {
  0% {
    transform: translate3d(0, -400px, 0);
  }
  100% {
    transform: translate3d(0, 40%, 0) rotateX(30deg) rotateY(0deg) rotateZ(60deg);
  }
}
@keyframes laydown {
  0% {
    transform: translate3d(0, 40%, 0) rotateX(30deg) rotateY(0deg) rotateZ(60deg);
  }
  100% {
    transform: translate3d(0, 40%, 0) rotateX(70deg) rotateY(0deg) rotateZ(80deg);
  }
}
#falling-card-parent {
  height: 150px;
  width: 100px;
  margin: auto;
  perspective: 1000px;
}
#falling-card {
  height: 150px;
  width: 100px;
  background-color: black;
  margin: auto;
  transform: translate3d(0, 40%, 0) rotateX(70deg) rotateY(0deg) rotateZ(80deg);
  animation-name: falling, laydown;
  animation-duration: 2000ms, 1000ms;
  animation-delay: 0ms, 2000ms;
  animation-timing-function: ease-in, ease-out;
  animation-iteration-count: 1, 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div id="falling-card-parent">
  <div id="falling-card"></div>
</div>