Combining Multiple CSS Animations into One Overall Animation

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

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="Sample Image" width="120" height="120">
<div>

Combine multiple animations

Can I combine these two animations?

I assume by combine you mean producing forward (on click of add animation) and reverse (on click of remove animation) animations using the same keyframe rules. It's possible to achieve but for that both the forward and reverse animations should be exactly the same (but in opposite directions). When it is same, we can use animation-direction: reverse to achieve reverse effect with same keyframes.

Here, the forward animation has a transform change whereas the reverse doesn't and hence adding animation-direction: reverse would not produce the same effect as the original snippet. Moreover, coding it is not as easy as just adding a property also, a lot of work is needed like mentioned here.


What is the reason for the other two issues?

The reason for both the issues (that is, the element getting opacity: 1 immediately when the remove button is clicked and element getting full size when remove button is clicked while forward animation is still happening) are the same. When you remove the animation on an element (by removing the class) it immediately snaps to the size specified outside of the animation.

For the first case, the size is the one that is mentioned under .element (as .one is removed) and its opacity is default 1 because there is no opacity setting in it. For the second case, when the .one is removed and .two is added, the animation is removed and so the element's size is as specified in .element and the opacity is as specified in .two (because that is later in CSS file).


So what else is the alternate?

When both forward and reverse effects are required and the animation doesn't have any intermediate states (that is, there is only a start state and an end state) then it is better to use transitions instead of animations. The reason is because transitions automatically produce the reverse effect on removal of the class (unlike animations where the reverse animation needs to be written as a separate keyframe and added to the element).

Below is a sample snippet showing how you can achieve a similar effect using just one class without the need for writing keyframes.

 var theBut = document.getElementById('butt'); var theBut2 = document.getElementById('butt2'); theBut.addEventListener('click', function a() {   document.querySelector('.element').classList.add('one'); });
theBut2.addEventListener('click', function b() { document.querySelector('.element').classList.remove('one'); });
.element {  background-color: #d91e57;  display: block;  width: 160px;  height: 160px;  border-radius: 90%;  transform: scale(0.25);  opacity: 0;  transition: opacity 2s, transform .1s 2s;}.one {  transform: scale(1);  opacity: 0.5;  transition: all 2s;}
<div class="element"></div><button id="butt">add animation</button><button id='butt2'>remove animation</button>

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>

LESS: Combine multiple CSS3 animation

Thanks to @seven-phases-max's suggestion, I elaborated a possible solution, pipelining animations in case more than one CSS class is assigned to an element.

Here my original (now slightly modified) code, in which I move common parts in dedicated COMMONS mixins:

.color_animation (@color, @time:1s)
{
@stop-1:~"@{color}_SOPRA";
@stop-2:~"@{color}_SOTTO";

@name: ~"blink-@{color}";

.steps()
{
0% { color:@@stop-1; }
100% { color:@@stop-2; }
}

@value:@name @time ease-in-out infinite alternate;

.INITIALIZE_keyframes();
.CALL_animation();
}

.zoom_animation (@ratio, @time:1s)
{
@zoom-ratio:round(@ratio*100);
@name: ~"zoom-@{zoom-ratio}";

.steps()
{
0% { .scale(1.0); }
100% { .scale(@ratio); }
}

@value:@name @time ease-in-out infinite alternate;

.INITIALIZE_keyframes();
.CALL_animation();
}

Here the COMMONS mixins declaration (I'm missing browsers browsers prefix for simplicity, but they could be added here):

.INITIALIZE_keyframes()
{
@keyframes @name { .steps(); }
}

.CALL_animation()
{
animation+:@value;
}

Please, note the '+' sign in animation declaration, it's the secret of my solution, coupled with the following CSS classes declaration:

.blink
{
.color_animation(red);
}

.animated-zoom
{
.zoom_animation(1.05);
}

.blink
{
&.animated-zoom
{
.color_animation(red);
.animated-zoom;
}
}

Repeat multiple css animations

How it works?

1: Animation duration / no. of elements = animation delay

2: You need to tweak keyframe animation as per your requirements(this may vary). You need have instinct on time appearance of your each element & time gap.

3: And add animation-iteration-count: infinite; to your individual element.

body {  font-size: 62.5%;  font-family: Arial;}
.animation-box { width: 75%; height: 30rem; background-color: darkblue; margin: 0 auto; overflow: hidden; position: relative;}
@keyframes fadeInOut { 0% {opacity: 0;}
2% {opacity: 0;}
5% {opacity: 1;}
17% {opacity: 1;}
19% {opacity: 1;}
24% {opacity: 0;}
80% {opacity: 0;}
100% {opacity: 0;}}
.animation-box h1 { position: absolute; left: 5%; top: 0; font-size: 4em; color: white; font-weight: 400;}
.first-line,.second-line,.third-line,.fourth-line { font-size: 3em; position: absolute; left: 5%; top: 20%; opacity: 0; color: rgba(200,200,200,0.9); animation-name: fadeInOut; animation-iteration-count: infinite;}
.first-line { animation-duration: 12s;}
.second-line { animation-delay: 3s; animation-duration: 12s;}
.third-line { animation-delay: 6s; animation-duration: 12s; }
.fourth-line { animation-delay: 9s; animation-duration: 12s;}
<section class="animation-box">    <h1>Fading the lines</h1>       <div class="first-line">This is line 1</div>    <div class="second-line">here comes line 2</div>    <div class="third-line">3 is the perfect number</div>    <div class="fourth-line">the final one is 4</div>  </section>


Related Topics



Leave a reply



Submit