Play Multiple CSS Animations At the Same Time

Play multiple CSS animations at the same time

TL;DR

With a comma, you can specify multiple animations each with their own properties as stated in the CriticalError answer below.

Example:

animation: rotate 1s, spin 3s;

Original answer

There are two issues here:

#1

-webkit-animation:spin 2s linear infinite;
-webkit-animation:scale 4s linear infinite;

The second line replaces the first one. So, has no effect.

#2

Both keyframes applies on the same property transform

As an alternative you could to wrap the image in a <div> and animate each one separately and at different speeds.

http://jsfiddle.net/rnrlabs/x9cu53hp/

.scaler {
position: absolute;
top: 100%;
left: 50%;
width: 120px;
height: 120px;
margin:-60px 0 0 -60px;
animation: scale 4s infinite linear;
}

.spinner {
position: relative;
top: 150px;
animation: spin 2s infinite linear;
}


@keyframes spin {
100% {
transform: rotate(180deg);
}
}

@keyframes scale {
100% {
transform: scaleX(2) scaleY(2);
}
}
<div class="spinner">
<img class="scaler" src="http://makeameme.org/media/templates/120/grumpy_cat.jpg" alt="" width="120" height="120">
<div>

Chaining Multiple CSS Animations

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>

Having multiple animations at the same time CSS3

I would probably merge them into only one animation that you can easily manage without any synchronisation issue.

@keyframes changeContent {  0% {    color: #fbd977;    content: "\f1fe";    transform: rotate(15deg);  }  5% {    transform: rotate(0deg);  }  19.99% {    content: '\f1fe';    color: #fbd977;    transform: rotate(0deg);  }  20.00% {    color: #ed9286;    content: "\f201";    transform: rotate(15deg);  }  25% {    transform: rotate(0deg);  }  39.99% {    content: "\f201";    color: #ed9286;    transform: rotate(0deg);  }  40.00% {    color: #d992bc;    content: '\f200';    transform: rotate(15deg);  }  45% {    transform: rotate(0deg);  }  59.99% {    content: '\f200';    color: #d992bc;    transform: rotate(0deg);  }  60.00% {    color: #84bbe6;    content: '\f080';    transform: rotate(15deg);  }  65% {    transform: rotate(0deg);  }  79.99% {    color: #84bbe6;    content: '\f080';    transform: rotate(0deg);  }  80.00% {    color: #aed292;    content: '\f0ce';    transform: rotate(15deg);  }  85% {    transform: rotate(0deg);  }  99.99% {    color: #aed292;    content: '\f0ce';    transform: rotate(0deg);  }}
.fa:before { animation: changeContent 10s infinite; display:inline-block; /* Don't forget this to be able to use transform */ transform-origin: center bottom;}
.fa { font-size: 5em!important;}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<div id="loading"> <span class="foo fa-fw fa fa-area-chart"></span></div>

Combining multiple CSS animations into one overall animation

One animation one element is how it works as the animations change the styles of a single element. You can however apply delays to the animations to achieve what you want, allowing you to move pretty much everything out of JS.

This example merges your .outside an .inside animations, by basically appending them with a comma to the rule and you JS now just adds the class like this -webkit-animation-name: button-bounce, rotate, skyblue;

jsFiddle

CSS

.outside.animate {
-webkit-animation-delay: 0s, .5s, .5s;
-webkit-animation-duration: 500ms, 1000ms, 1000ms;
-webkit-animation-name: button-bounce, rotate, skyblue;
}

.animate {
-webkit-animation-fill-mode: forwards;
-webkit-animation-timing-function: ease;
-webkit-transform: translateZ(0);
}

.outside.animate .inside {
-webkit-animation-delay: .5s, .5s, 1.5s;
-webkit-animation-duration: 1000ms, 1000ms, 750ms;
-webkit-animation-name: rotate, magenta, scale-in;
}

New animations

@-webkit-keyframes magenta {
0% { border: 1px solid magenta; }
99.99% { border: 1px solid magenta; }
100% { border: 1px solid skyblue; }
}
@-webkit-keyframes skyblue {
0% { border: 1px solid skyblue; }
99.99% { border: 1px solid skyblue; }
100% { border: 1px solid magenta; }
}

JavaScript

$(document).ready(function() {
$(document).click(function() {
var count = 0;
var jqElement = $('.outside');
if (!jqElement.hasClass('animate')) {
jqElement.addClass('animate');
jqElement.on('animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd', function(event) {
count++;
if (count >= 6) {
jqElement.off('animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd');
jqElement.removeClass('animate');
}
});
}
});
});

CSS multiple animation with different delay

Add the delay after the easing (AKA timing-function) value.

div{
width: 200px;
height: 200px;
background: red;
animation: animScale 2000ms ease-in-out 1000ms infinite,
animOpacity 2000ms ease-in-out 2000ms infinite;
/* scale will start after 1s and opacity after 2s (1s after the scale)*/
}

The values order for the animation shorthand goes as:

animation-name: name

animation-duration: 0

animation-timing-function: ease

animation-delay: 0

animation-iteration-count: 1

animation-direction: normal

animation-fill-mode: none

animation-play-state: running

Read more: https://developer.mozilla.org/en-US/docs/Web/CSS/animation

CSS chain multiple animations from different classes

There must be a better way probably but that is what i got and i think it will solve your problem

So i collect boxes x and y coordinates when animation button clicks and after the animationend event, i collect both x and y coordinates again and calculate difference of them and add to box style.

const firstButton = document.querySelectorAll('button')[0];

const secondButton = document.querySelectorAll('button')[1];

const myBox = document.querySelector('div')

let rectBefore;
let rectAfter;
let positionBeforeX;
let positionBeforeY;
let positionAfterX;
let positionAfterY;

let differenceX;
let differenceY;


firstButton.addEventListener('click', () => {
rectBefore = myBox.getBoundingClientRect();
positionBeforeX = rectBefore.left;
positionBeforeY = rectBefore.top;

myBox.classList.toggle('first');
})

secondButton.addEventListener('click', () => {
rectBefore = myBox.getBoundingClientRect();
positionBeforeX = rectBefore.left;
positionBeforeY = rectBefore.top;

myBox.classList.toggle('second');

})

myBox.addEventListener('animationend', (event) =>{
rectAfter = myBox.getBoundingClientRect();
positionAfterX = rectAfter.left;
positionAfterY = rectAfter.top;

differenceX = positionAfterX - positionBeforeX;
differenceY = positionAfterY - positionBeforeY;

if(myBox.style.left !== ""){
myBox.style.left = `${parseInt(myBox.style.left.split('px')) + differenceX}px`;
myBox.style.top = `${parseInt(myBox.style.top.split('px')) + differenceY}px`;
}
else{
myBox.style.left = `${differenceX}px`;
myBox.style.top = `${differenceY}px`;
}

myBox.classList.remove(`${event.animationName}`);
})
*,
*::before,
*::after {
box-sizing: border-box;
}

body{
min-height: 100vh;
position: relative;
display: grid;
place-content: center;
}

button{
position: absolute;
background-color: greenyellow;
width: 5rem;
height: 5rem;

}

button:nth-of-type(1){
top:5rem;
right: 10rem;
margin-right: 1rem;
}

button:nth-of-type(2){
top:5rem;
right: 5rem;
}

.box{
position:relative;
width: 100px;
height: 100px;
background-color: blue;

}

.first {
animation: first 3.0s linear forwards;
}

.second {
animation: second 3.0s linear forwards;
}

@keyframes first {
20% {
transform: translate(50px, 0px);
}
40% {
transform: translate(50px, 0px) rotate(-90deg);
}
80% {
transform: translate(50px, -130px) rotate(-90deg);
}
100% {
transform: translate(50px, -125px) rotate(0deg);
}
}

@keyframes second {
20% {
transform: translate(100px, 0px);
}
40% {
transform: translate(100px, 0px) rotate(-90deg);
}
100% {
transform: translate(100px, -50px) rotate(-90deg);
}
}
<div class="box"></div>

<button>First Animation</button>
<button>Second Animation</button>


Related Topics



Leave a reply



Submit