Why are CSS keyframe animations broken in Vue components with scoped styling? - javascript

I'm trying to implement a CSS typing indicator in Vue. Without Vue, it looks like this:
.typing-indicator {
background-color: #E6E7ED;
width: auto;
border-radius: 50px;
padding: 20px;
display: table;
margin: 0 auto;
position: relative;
-webkit-animation: 2s bulge infinite ease-out;
animation: 2s bulge infinite ease-out;
}
.typing-indicator:before, .typing-indicator:after {
content: '';
position: absolute;
bottom: -2px;
left: -2px;
height: 20px;
width: 20px;
border-radius: 50%;
background-color: #E6E7ED;
}
.typing-indicator:after {
height: 10px;
width: 10px;
left: -10px;
bottom: -10px;
}
.typing-indicator span {
height: 15px;
width: 15px;
float: left;
margin: 0 1px;
background-color: #9E9EA1;
display: block;
border-radius: 50%;
opacity: 0.4;
}
.typing-indicator span:nth-of-type(1) {
-webkit-animation: 1s blink infinite 0.3333s;
animation: 1s blink infinite 0.3333s;
}
.typing-indicator span:nth-of-type(2) {
-webkit-animation: 1s blink infinite 0.6666s;
animation: 1s blink infinite 0.6666s;
}
.typing-indicator span:nth-of-type(3) {
-webkit-animation: 1s blink infinite 0.9999s;
animation: 1s blink infinite 0.9999s;
}
#-webkit-keyframes blink {
50% {
opacity: 1;
}
}
#keyframes blink {
50% {
opacity: 1;
}
}
#-webkit-keyframes bulge {
50% {
-webkit-transform: scale(1.05);
transform: scale(1.05);
}
}
#keyframes bulge {
50% {
-webkit-transform: scale(1.05);
transform: scale(1.05);
}
}
html {
display: table;
height: 100%;
width: 100%;
}
body {
display: table-cell;
vertical-align: middle;
}
<div class="typing-indicator">
<span></span>
<span></span>
<span></span>
</div>
– source: http://jsfiddle.net/Arlina/gtttgo93/
The problem is that the animation does not work when adding the scoped attribute to the component's style definition (<style lang="scss" scoped>). I believe it may be related to keyframes that should be declared globally.
The element with .typing-indicator is in the template of the component with scoped styling.
Does anyone have an idea of how I can allow my component to have scoped styling while making the keyframe animations work?

Problem
The problem is down to how the Webpack loader for Vue (vue-loader), incorrectly, parses animation names when adding IDs to scoped selectors and other identifiers. This is important because vue-loader's CSS scoping uses unique attributes added to elements to replicate the behaviour of CSS scoping. While your keyframe names get IDs appended, references to keyframes in animation rules in scoped styles do not.
Your CSS:
#-webkit-keyframes blink {
50% {
opacity: 1;
}
}
#keyframes blink {
50% {
opacity: 1;
}
}
#-webkit-keyframes bulge {
50% {
-webkit-transform: scale(1.05);
transform: scale(1.05);
}
}
#keyframes bulge {
50% {
-webkit-transform: scale(1.05);
transform: scale(1.05);
}
}
.typing-indicator {
...
-webkit-animation: 2s bulge infinite ease-out;
animation: 2s bulge infinite ease-out;
}
.typing-indicator span:nth-of-type(1) {
-webkit-animation: 1s blink infinite 0.3333s;
animation: 1s blink infinite 0.3333s;
}
.typing-indicator span:nth-of-type(2) {
-webkit-animation: 1s blink infinite 0.6666s;
animation: 1s blink infinite 0.6666s;
}
.typing-indicator span:nth-of-type(3) {
-webkit-animation: 1s blink infinite 0.9999s;
animation: 1s blink infinite 0.9999s;
}
Should get transformed to:
#-webkit-keyframes blink-data-v-xxxxxxxx {
50% {
opacity: 1;
}
}
#keyframes blink-data-v-xxxxxxxx {
50% {
opacity: 1;
}
}
#-webkit-keyframes bulge-data-v-xxxxxxxx {
50% {
-webkit-transform: scale(1.05);
transform: scale(1.05);
}
}
#keyframes bulge-data-v-xxxxxxxx {
50% {
-webkit-transform: scale(1.05);
transform: scale(1.05);
}
}
.typing-indicator {
...
-webkit-animation: 2s bulge-data-v-xxxxxxxx infinite ease-out;
animation: 2s bulge-data-v-xxxxxxxx infinite ease-out;
}
.typing-indicator span:nth-of-type(1) {
-webkit-animation: 1s blink-data-v-xxxxxxxx infinite 0.3333s;
animation: 1s blink-data-v-xxxxxxxx infinite 0.3333s;
}
.typing-indicator span:nth-of-type(2) {
-webkit-animation: 1s blink-data-v-xxxxxxxx infinite 0.6666s;
animation: 1s blink-data-v-xxxxxxxx infinite 0.6666s;
}
.typing-indicator span:nth-of-type(3) {
-webkit-animation: 1s blink-data-v-xxxxxxxx infinite 0.9999s;
animation: 1s blink-data-v-xxxxxxxx infinite 0.9999s;
}
However it only get's transformed to:
#-webkit-keyframes blink-data-v-xxxxxxxx {
50% {
opacity: 1;
}
}
#keyframes blink-data-v-xxxxxxxx {
50% {
opacity: 1;
}
}
#-webkit-keyframes bulge-data-v-xxxxxxxx {
50% {
-webkit-transform: scale(1.05);
transform: scale(1.05);
}
}
#keyframes bulge-data-v-xxxxxxxx {
50% {
-webkit-transform: scale(1.05);
transform: scale(1.05);
}
}
.typing-indicator {
...
-webkit-animation: 2s bulge infinite ease-out;
animation: 2s bulge infinite ease-out;
}
.typing-indicator span:nth-of-type(1) {
-webkit-animation: 1s blink infinite 0.3333s;
animation: 1s blink infinite 0.3333s;
}
.typing-indicator span:nth-of-type(2) {
-webkit-animation: 1s blink infinite 0.6666s;
animation: 1s blink infinite 0.6666s;
}
.typing-indicator span:nth-of-type(3) {
-webkit-animation: 1s blink infinite 0.9999s;
animation: 1s blink infinite 0.9999s;
}
Something to note: in the actual transformation, references to keyframe names in animation rules are missing the -data-v-xxxxxxxx at the end. This is the bug.
Currently (as of 47c3317) the animation name in shorthand animation rule declarations is identified by getting the first value out of splitting the animation rule by any whitespace character[1]. However the formal definition for the animation property states the animation name could appear anywhere within the rule definition.
<single-animation> = <time> || <single-timing-function> || <time> || <single-animation-iteration-count> || <single-animation-direction> || <single-animation-fill-mode> || <single-animation-play-state> || [ none | <keyframes-name> ]
– animation formal syntax[2]
Therefore, while your animation declarations are valid, vue-loader is not able to parse it.
Workaround
The current workaround for this is to move your animation names to the beginning of animation rule declarations. Your keyframe declarations do not need changing, they remain inside the scoped stylesheet. Your animation declarations should now look like this:
.typing-indicator {
...
-webkit-animation: bulge 2s infinite ease-out;
animation: bulge 2s infinite ease-out;
}
.typing-indicator span:nth-of-type(1) {
-webkit-animation: blink 1s infinite 0.3333s;
animation: blink 1s infinite 0.3333s;
}
.typing-indicator span:nth-of-type(2) {
-webkit-animation: blink 1s infinite 0.6666s;
animation: blink 1s infinite 0.6666s;
}
.typing-indicator span:nth-of-type(3) {
-webkit-animation: blink 1s infinite 0.9999s;
animation: blink 1s infinite 0.9999s;
}
References
[1] vue-loader/lib/style-compiler/plugins/scope-id.js#L67 # 47c3317
[2] Definition for animation in the Editor's Draft of W3C specification CSS Animations Level 1

I met the same problem and the first answer did tell me why it does not work, but the workaround part did not quite fix my issue... this is my code:
/* Animations */
#keyframes moveOut1 {
from {
transform: translateY(0) scale(0);
}
3% {
transform: translateY(0.2em) scale(1);
}
97% {
transform: translateY(7.3em) scale(1);
}
to {
transform: translateY(7.5em) scale(0);
}
}
#keyframes moveOut2 {
from {
transform: rotate(60deg) translateY(0) scale(0);
}
3% {
transform: rotate(60deg) translateY(0.2em) scale(1);
}
97% {
transform: rotate(60deg) translateY(7.3em) scale(1);
}
to {
transform: rotate(60deg) translateY(7.5em) scale(0);
}
}
#keyframes moveOut3 {
from {
transform: rotate(120deg) translateY(0) scale(0);
}
3% {
transform: rotate(120deg) translateY(0.2em) scale(1);
}
97% {
transform: rotate(120deg) translateY(7.3em) scale(1);
}
to {
transform: rotate(120deg) translateY(7.5em) scale(0);
}
}
#keyframes moveOut4 {
from {
transform: rotate(180deg) translateY(0) scale(0);
}
3% {
transform: rotate(180deg) translateY(0.2em) scale(1);
}
97% {
transform: rotate(180deg) translateY(7.3em) scale(1);
}
to {
transform: rotate(180deg) translateY(7.5em) scale(0);
}
}
#keyframes moveOut5 {
from {
transform: rotate(240deg) translateY(0) scale(0);
}
3% {
transform: rotate(240deg) translateY(0.2em) scale(1);
}
97% {
transform: rotate(240deg) translateY(7.3em) scale(1);
}
to {
transform: rotate(240deg) translateY(7.5em) scale(0);
}
}
#keyframes moveOut6 {
from {
transform: rotate(300deg) translateY(0) scale(0);
}
3% {
transform: rotate(300deg) translateY(0.2em) scale(1);
}
97% {
transform: rotate(300deg) translateY(7.3em) scale(1);
}
to {
transform: rotate(300deg) translateY(7.5em) scale(0);
}
}
#keyframes ripple {
from,
to {
width: 0.2em;
}
33% {
width: 2.4em;
}
}
so I asked a friend and the solution he provided me with is simply to place the css code out side and then import it into the vue component via
<style>
#import url(./{css_file_name}.css);
</style>
but I do not understand the mechanism behind this... but to me, it's fine as long as it works.

Related

Restart CSS3 animation using Javascript

I'm creating a CSS3/HTML5 banner ad and want to loop the animations over once they're all complete. I know there's a method to check with Javascript to check if a particular animation has ended, however I cannot figure out how to then restart the animations from all of their start points.
Essentially I have 3 'frames' with different information, each one will fade in and then fade back out, to be replaced with the next frame - once the last frame has faded back out, I want the animations to start over again. Doing this solely with CSS3 is way too tricky, because the timings of the animations and points in which the opacity is set to 0 have to be different for each animation.
As you can see from the JSFiddle, it plays once, then stops which is great, now I just need to re-trigger the animation once click_through2 finishes executing the animation.
JSFiddle
.test {
height: 250px;
position: relative;
width: 300px;
overflow: hidden;
}
.test div, .test a, .logo, .sfv2 {
position: absolute;
}
.title {
bottom: 45px;
left: 5px;
right: 5px;
}
.title h2 {
color: #fff;
font-family: Helvetica,arial,sans-serif;
font-size: 21px;
font-weight: 400;
line-height: 1;
margin: 0;
text-align: center;
}
.click_through {
background-color: #fff200;
border-radius: 5px;
bottom: 12px;
box-shadow: 0 0 15px rgba(0, 0, 0, 0.35);
color: #ce1e25;
font-family: Helvetica,arial,sans-serif;
font-size: 14px;
font-weight: 700;
left: 0;
line-height: 1;
margin: 0 auto;
padding: 5px;
right: 0;
text-align: center;
width: 70px;
text-decoration: none;
}
.click_through1 {
animation: tbio 7s ease-out 0s both;
-moz-animation: tbio 7s ease-out 0s both;
-webkit-animation: tbio 7s ease-out 0s both;
-ms-animation: tbio 7s ease-out 0s both;
-o-animation: tbio 7s ease-out 0s both;
}
.click_through2 {
animation: tbio 7s ease-out 10s both;
-moz-tbio tbio 7s ease-out 10s both;
-webkit-tbio tbio 7s ease-out 10s both;
-ms-tbio tbio 7s ease-out 10s both;
-o-tbio tbio 7s ease-out 10s both;
width: 80px;
}
.logo {
top: 8px;
left: 8px;
}
.title1 {
animation: ltrio 6s ease 0s both;
-moz-animation: ltrio 6s ease 0s both;
-webkit-animation: ltrio 6s ease 0s both;
-ms-animation: ltrio 6s ease 0s both;
-o-animation: ltrio 6s ease 0s both;
}
.title2, .title3 {
opacity: 0;
}
.title2 {
animation: ltrio 6s ease 5.5s both;
-moz-animation: ltrio 6s ease 5.5s both;
-webkit-animation: ltrio 6s ease 5.5s both;
-ms-animation: ltrio 6s ease 5.5s both;
-o-animation: ltrio 6s ease 5.5s both;
}
.title3 {
animation: ltrio 6s ease 10s both;
-moz-nimation: ltrio 6s ease 10s both;
-webkit-nimation: ltrio 6s ease 10s both;
-ms-onimation: ltrio 6s ease 10s both;
-o-nimation: ltrio 6s ease 10s both;
}
.sfv2 {
right: 12px;
top: 34px;
animation: fio 6s ease 11s both;
-moz-animation: fio 6s ease 11s both;
-webkit-animation: fio 6s ease 11s both;
-ms-animation: fio 6s ease 11s both;
-o-animation: fio 6s ease 11s both;
}
#keyframes ltrio {
0% {
opacity: 0;
}
20% {
opacity: 1;
}
50% {
opacity: 1;
}
80% {
opacity: 0;
}
100% {
opacity: 0;
}
}
#-moz-keyframes ltrio {
0% {
opacity: 0;
}
20% {
opacity: 1;
}
50% {
opacity: 1;
}
80% {
opacity: 0;
}
100% {
opacity: 0;
}
}
#-ms-keyframes ltrio {
0% {
-ms-transform: translateY(-350px);
opacity: 0;
}
25% {
-ms-transform: translateY(0);
opacity: 1;
}
75% {
-ms-transform: translateY(0);
opacity: 1;
}
100% {
-ms-transform: translateY(350px);
opacity: 0;
}
}
#-o-keyframes ltrio {
0% {
-o-transform: translateX(-350px);
opacity: 0;
}
25% {
-o-transform: translateX(0);
opacity: 1;
}
75% {
-o-transform: translateX(0);
opacity: 1;
}
100% {
-o-transform: translateX(350px);
opacity: 0;
}
}
#keyframes tbio {
0% {
transform: translateY(350px);
opacity: 0;
}
25% {
transform: translateY(0);
opacity: 1;
}
75% {
transform: translateY(0);
opacity: 1;
}
100% {
transform: translateY(350px);
opacity: 0;
}
}
#-moz-keyframes tbio {
0% {
-moz-transform: translateY(350px);
opacity: 0;
}
25% {
-moz-transform: translateY(0);
opacity: 1;
}
75% {
-moz-transform: translateY(0);
opacity: 1;
}
100% {
-moz-transform: translateY(350px);
opacity: 0;
}
}
#-webkit-keyframes tbio {
0% {
-webkit-transform: translateY(350px);
opacity: 0;
}
25% {
-webkit-transform: translateY(0);
opacity: 1;
}
75% {
-webkit-transform: translateY(0);
opacity: 1;
}
100% {
-webkit-transform: translateY(350px);
opacity: 0;
}
}
#-ms-keyframes tbio {
0% {
-ms-transform: translateY(350px);
opacity: 0;
}
25% {
-ms-transform: translateY(0);
opacity: 1;
}
75% {
-ms-transform: translateY(0);
opacity: 1;
}
100% {
-ms-transform: translateY(350px);
opacity: 0;
}
}
#-o-keyframes tbio {
0% {
-o-transform: translateY(350px);
opacity: 0;
}
25% {
-o-transform: translateY(0);
opacity: 1;
}
75% {
-o-transform: translateY(0);
opacity: 1;
}
100% {
-o-transform: translateY(350px);
opacity: 0;
}
}
#keyframes fio {
0% {
opacity: 0;
}
20% {
opacity: 1;
}
50% {
opacity: 1;
}
80% {
opacity: 0;
}
100% {
opacity: 0;
}
}
<div class="test">
<img class="sfv1" src="http://i.imgur.com/3VWKopF.jpg">
<div class="title title1">
<h2>Great value<br/> <strong>Spanish Properties</strong><br/> starting at £65k</h2>
</div>
<div class="title title2">
<h2>Stunning properties in <br/><strong>Costa del Sol, <br/>Blanca & Murcia</strong></h2>
</div>
<div class="title title3">
<h2>Over <strong>10,000 <br/>Spanish properties sold</strong></h2>
</div>
<a class="click_through click_through1" href="/">View here</a>
<a class="click_through click_through2" href="/">Learn more</a>
</div>
You could check for the end of the animation by responding to the endanimation event (of which there are several browser-dependent variants), reloading the relevant nodes, and repeating the whole process. Note I applied a factor 10 to the speed of the animations so you can see the effect faster:
// Define a function that listens to all prefix variants of endanimation events:
function whenAnimationEnd(element, callback) {
element.addEventListener('animationend', callback, false);
element.addEventListener('webkitAnimationEnd', callback, false);
element.addEventListener('oanimationend', callback, false);
element.addEventListener('MSAnimationEnd', callback, false);
}
(function repeat() {
whenAnimationEnd(document.querySelector('.click_through2'), function(e) {
var container = document.querySelector('.ad_container');
var dupe = container.cloneNode(true);
container.parentNode.replaceChild(dupe, container);
repeat();
});
}());
.ad_container {
height: 250px;
position: relative;
width: 300px;
overflow: hidden;
}
.ad_container div, .ad_container a, .logo, .sfv2 {
position: absolute;
}
.title {
bottom: 45px;
left: 5px;
right: 5px;
}
.title h2 {
color: #fff;
font-family: Helvetica,arial,sans-serif;
font-size: 21px;
font-weight: 400;
line-height: 1;
margin: 0;
text-align: center;
}
.click_through {
background-color: #fff200;
border-radius: 5px;
bottom: 12px;
box-shadow: 0 0 15px rgba(0, 0, 0, 0.35);
color: #ce1e25;
font-family: Helvetica,arial,sans-serif;
font-size: 14px;
font-weight: 700;
left: 0;
line-height: 1;
margin: 0 auto;
padding: 5px;
right: 0;
text-align: center;
width: 70px;
text-decoration: none;
}
.click_through1 {
animation: tbio 0.7s ease-out 0s both;
-moz-animation: tbio 0.7s ease-out 0s both;
-webkit-animation: tbio 0.7s ease-out 0s both;
-ms-animation: tbio 0.7s ease-out 0s both;
-o-animation: tbio 0.7s ease-out 0s both;
}
.click_through2 {
animation: tbio 0.7s ease-out 1s both;
-moz-tbio tbio 0.7s ease-out 1s both;
-webkit-tbio tbio 0.7s ease-out 1s both;
-ms-tbio tbio 0.7s ease-out 1s both;
-o-tbio tbio 0.7s ease-out 1s both;
width: 80px;
}
.logo {
top: 8px;
left: 8px;
}
.title1 {
animation: ltrio 0.6s ease 0s both;
-moz-animation: ltrio 0.6s ease 0s both;
-webkit-animation: ltrio 0.6s ease 0s both;
-ms-animation: ltrio 0.6s ease 0s both;
-o-animation: ltrio 0.6s ease 0s both;
}
.title2, .title3 {
opacity: 0;
}
.title2 {
animation: ltrio 0.6s ease 0.55s both;
-moz-animation: ltrio 0.6s ease 0.55s both;
-webkit-animation: ltrio 0.6s ease 0.55s both;
-ms-animation: ltrio 0.6s ease 0.55s both;
-o-animation: ltrio 0.6s ease 0.55s both;
}
.title3 {
animation: ltrio 0.6s ease 1s both;
-moz-nimation: ltrio 0.6s ease 1s both;
-webkit-nimation: ltrio 0.6s ease 1s both;
-ms-onimation: ltrio 0.6s ease 1s both;
-o-nimation: ltrio 0.6s ease 1s both;
}
.sfv2 {
right: 12px;
top: 34px;
animation: fio 0.6s ease 1.1s both;
-moz-animation: fio 0.6s ease 1.1s both;
-webkit-animation: fio 0.6s ease 1.1s both;
-ms-animation: fio 0.6s ease 1.1s both;
-o-animation: fio 0.6s ease 1.1s both;
}
#keyframes ltrio {
0% {
opacity: 0;
}
20% {
opacity: 1;
}
50% {
opacity: 1;
}
80% {
opacity: 0;
}
100% {
opacity: 0;
}
}
#-moz-keyframes ltrio {
0% {
opacity: 0;
}
20% {
opacity: 1;
}
50% {
opacity: 1;
}
80% {
opacity: 0;
}
100% {
opacity: 0;
}
}
#-ms-keyframes ltrio {
0% {
-ms-transform: translateY(-350px);
opacity: 0;
}
25% {
-ms-transform: translateY(0);
opacity: 1;
}
75% {
-ms-transform: translateY(0);
opacity: 1;
}
100% {
-ms-transform: translateY(350px);
opacity: 0;
}
}
#-o-keyframes ltrio {
0% {
-o-transform: translateX(-350px);
opacity: 0;
}
25% {
-o-transform: translateX(0);
opacity: 1;
}
75% {
-o-transform: translateX(0);
opacity: 1;
}
100% {
-o-transform: translateX(350px);
opacity: 0;
}
}
#keyframes tbio {
0% {
transform: translateY(350px);
opacity: 0;
}
25% {
transform: translateY(0);
opacity: 1;
}
75% {
transform: translateY(0);
opacity: 1;
}
100% {
transform: translateY(350px);
opacity: 0;
}
}
#-moz-keyframes tbio {
0% {
-moz-transform: translateY(350px);
opacity: 0;
}
25% {
-moz-transform: translateY(0);
opacity: 1;
}
75% {
-moz-transform: translateY(0);
opacity: 1;
}
100% {
-moz-transform: translateY(350px);
opacity: 0;
}
}
#-webkit-keyframes tbio {
0% {
-webkit-transform: translateY(350px);
opacity: 0;
}
25% {
-webkit-transform: translateY(0);
opacity: 1;
}
75% {
-webkit-transform: translateY(0);
opacity: 1;
}
100% {
-webkit-transform: translateY(350px);
opacity: 0;
}
}
#-ms-keyframes tbio {
0% {
-ms-transform: translateY(350px);
opacity: 0;
}
25% {
-ms-transform: translateY(0);
opacity: 1;
}
75% {
-ms-transform: translateY(0);
opacity: 1;
}
100% {
-ms-transform: translateY(350px);
opacity: 0;
}
}
#-o-keyframes tbio {
0% {
-o-transform: translateY(350px);
opacity: 0;
}
25% {
-o-transform: translateY(0);
opacity: 1;
}
75% {
-o-transform: translateY(0);
opacity: 1;
}
100% {
-o-transform: translateY(350px);
opacity: 0;
}
}
#keyframes fio {
0% {
opacity: 0;
}
20% {
opacity: 1;
}
50% {
opacity: 1;
}
80% {
opacity: 0;
}
100% {
opacity: 0;
}
}
<div class="ad_container">
<img class="sfv1" src="http://i.imgur.com/3VWKopF.jpg">
<div class="title title1">
<h2>Great value<br/> <strong>Spanish Properties</strong><br/> starting at £65k</h2>
</div>
<div class="title title2">
<h2>Stunning properties in <br/><strong>Costa del Sol, <br/>Blanca & Murcia</strong></h2>
</div>
<div class="title title3">
<h2>Over <strong>10,000 <br/>Spanish properties sold</strong></h2>
</div>
<a class="click_through click_through1" href="/">View here</a>
<a class="click_through click_through2" href="/">Learn more</a>
</div>
Use a setTimeout and try setting the animation property to something else and then set it to the classname again so that it restarts the animation.
Something like:
setTimeout(function(){
document.querySelector('.someclass').classList.remove("run-animation").classList.add("run-animation");
}, 1000)
Remove the class to which the animation is assigned to and add it again (maybe with timeout) and the animation starts again.

How to play different css animations one after another?

I'm trying to play different css animations one after another but I can't figure out how to.
Basically what I'm trying to do is play one Animation, have it on screen for 15 seconds, then play the next one, show it for 15 seconds and on to the next one and when the last one has been played, it should start again from the top.
Here's an example of the first one it should play, show for 15 seconds and then move on to the next one and do the same.
<style> #animated-example {
width: 300px;
height: 200px;
border: solid 1px #1A7404;
position: absolute;
background-color: #62A80A;
}
.animated {
-webkit-animation-duration: 2s;
animation-duration: 2s;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
}
#-webkit-keyframes bounceInLeft {
0% {
opacity: 0;
-webkit-transform: translateX(-2000px);
}
60% {
opacity: 1;
-webkit-transform: translateX(30px);
}
80% {
-webkit-transform: translateX(-10px);
}
100% {
-webkit-transform: translateX(0);
}
}
#keyframes bounceInLeft {
0% {
opacity: 0;
transform: translateX(-2000px);
}
60% {
opacity: 1;
transform: translateX(30px);
}
80% {
transform: translateX(-10px);
}
100% {
transform: translateX(0);
}
}
.bounceInLeft {
-webkit-animation-name: bounceInLeft;
animation-name: bounceInLeft;
}
</style>
<img id="animated-example" class="animated bounceInLeft" src="http://webmarketingtoday.com/wp-content/uploads/Screen-Shot-2012-05-24-at-7.31.54-AM-288x216.png">
And then run another one, show it for 15 seconds and move on.
<style> #animated-example {
width: 300px;
height: 200px;
border: solid 1px #1A7404;
position: absolute;
background-color: #62A80A;
}
.animated {
-webkit-animation-duration: 1s;
animation-duration: 1s;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
}
#-webkit-keyframes bounceInDown {
0% {
opacity: 0;
-webkit-transform: translateY(-2000px);
}
60% {
opacity: 1;
-webkit-transform: translateY(30px);
}
80% {
-webkit-transform: translateY(-10px);
}
100% {
-webkit-transform: translateY(0);
}
}
#keyframes bounceInDown {
0% {
opacity: 0;
transform: translateY(-2000px);
}
60% {
opacity: 1;
transform: translateY(30px);
}
80% {
transform: translateY(-10px);
}
100% {
transform: translateY(0);
}
}
.bounceInDown {
-webkit-animation-name: bounceInDown;
animation-name: bounceInDown;
}
</style>
<img id="animated-example" class="animated bounceInDown" src="https://www.facebookbrand.com/img/fb-art.jpg">
The only way to achieve that in pure CSS is to run all the animations at the same time and do some calculations:
the length of each animation should be the same and equal to the total length of desired animations (meaning if you want two 15-second animations, the CSS animations should be set to length of 30 seconds, no delays)
to control the start/end point of each animation, you need to modify the percentages accordingly - in the above case, it means that the first animation ends at 50% and that's when the second animation starts. Also, all in-between values need to be interpolated. It's easy for two animations, but you might need to use a calculator as the total number of animations increases. This is if we don't take the delays into account - the numbers change when we have a 15-second animation that will finish animation after 5 seconds, which now equals 33%, etc...
It will be more clear once you see it in action here:
.animated-example {
width: 300px;
height: 200px;
border: solid 1px #1A7404;
position: absolute;
background-color: #62A80A;
}
.animated {
animation-duration: 20s;
animation-fill-mode: both;
animation-iteration-count: infinite;
}
.bounceInLeft {
-webkit-animation-name: bounceInLeft;
animation-name: bounceInLeft;
}
.bounceInDown {
-webkit-animation-name: bounceInDown;
animation-name: bounceInDown;
}
#keyframes bounceInLeft {
0% {
opacity: 0;
transform: translateX(-2000px);
}
6% {
opacity: 1;
transform: translateX(30px);
}
8% {
transform: translateX(-10px);
}
10% {
transform: translateX(0);
}
40% {
opacity: 1;
transform: translateX(0);
}
42% {
opacity: 1;
transform: translateX(30px);
}
55% {
opacity: 0;
transform: translateX(-2000px);
}
100% {
opacity: 0;
transform: translateX(-2000px);
}
}
#keyframes bounceInDown {
0% {
opacity: 0;
transform: translateY(-2000px);
}
50% {
opacity: 0;
transform: translateY(-2000px);
}
56% {
opacity: 1;
transform: translateY(30px);
}
58% {
transform: translateY(-10px);
}
60% {
transform: translateY(0);
}
90% {
transform: translateY(0);
}
92% {
opacity: 1;
transform: translateY(30px);
}
100% {
opacity: 0;
transform: translateY(-2000px);
}
}
<img class="animated-example animated bounceInLeft" src="http://webmarketingtoday.com/wp-content/uploads/Screen-Shot-2012-05-24-at-7.31.54-AM-288x216.png">
<img class="animated-example animated bounceInDown" src="https://www.facebookbrand.com/img/fb-art.jpg">
Using animation-delay.
animation: a, b;
animation-duration: 2s, 2s;
animation-delay: 0s, 4s;
The animation b will start after 4s while animation a will start without any delay.
animation-delay would do exactly what you're looking for except for the fact that you want the animations to repeat after the last one has been completed; unfortunately there is (currently) no way to specify a delay between iterations of a looping animation.
You could, however, achieve what you're looking to do using a little bit of JavaScript, like the following. To add more animations, simply add their class names to the animations array at the start of the code.
var animations=["bounceInLeft","bounceInDown"],
count=animations.length,
classlist=document.querySelector("img").classList,
holder=document.createElement("div"),
style=window.getComputedStyle(holder),
delay=15,
current,wait,x;
holder.style.display="none";
document.body.appendChild(holder);
animate();
function animate(){
wait=0;
x=0;
while(x<count){
setTimeout(function(a){
classlist.remove(current);
classlist.add(a);
current=a;
},wait*1000,animations[x]);
holder.className=animations[x];
wait+=delay+parseInt(style.getPropertyValue("animation-duration"));
x++;
}
setTimeout(animate,wait*1000);
};
img{
animation-fill-mode:both;
height:200px;
width:300px;
}
.bounceInDown{
animation-duration:1s;
animation-name:bounceInDown;
}
.bounceInLeft{
animation-duration:2s;
animation-name:bounceInLeft;
}
#keyframes bounceInDown{
0%{
opacity:0;
transform:translateY(-2000px);
}
60%{
opacity:1;
transform:translateY(30px);
}
80%{
transform:translateY(-10px);
}
100%{
transform:translateY(0);
}
}
#keyframes bounceInLeft{
0%{
opacity:0;
transform:translateX(-2000px);
}
60%{
opacity:1;
transform:translateX(30px);
}
80%{
transform:translateX(-10px);
}
100%{
transform:translateX(0);
}
}
<img src="http://webmarketingtoday.com/wp-content/uploads/Screen-Shot-2012-05-24-at-7.31.54-AM-288x216.png">
I have managed to achieve something similar by adapting this concept by Noah Addy: http://digitalfio.github.io/Stagger.css/
You will need to work on the timings a bit to get the 15sec delay you want, but other than that it should be fairly straightforward.

Jquery dlmenu animation is not smooth

I have created multilevel navigation menu using jquery dlmenu plugin v1.0.2 demo2.
Everything works fine, except CSS3 menu navigation is not smooth as jQuery left/right slide functionality is.
Is there any solution to resolve this issue without changing plugin?
/* Animation classes for moving out and in */
.dl-menu.dl-animate-out-2 {
-webkit-animation: MenuAnimOut2 0.3s ease-in-out forwards;
-moz-animation: MenuAnimOut2 0.3s ease-in-out forwards;
animation: MenuAnimOut2 0.3s ease-in-out forwards;
}
#-webkit-keyframes MenuAnimOut2 {
100% {
-webkit-transform: translateX(-100%);
opacity: 0;
}
}
#-moz-keyframes MenuAnimOut2 {
100% {
-moz-transform: translateX(-100%);
opacity: 0;
}
}
#keyframes MenuAnimOut2 {
100% {
transform: translateX(-100%);
opacity: 0;
}
}
.dl-menu.dl-animate-in-2 {
-webkit-animation: MenuAnimIn2 0.3s ease-in-out forwards;
-moz-animation: MenuAnimIn2 0.3s ease-in-out forwards;
animation: MenuAnimIn2 0.3s ease-in-out forwards;
}
#-webkit-keyframes MenuAnimIn2 {
0% {
-webkit-transform: translateX(-100%);
opacity: 0;
}
100% {
-webkit-transform: translateX(0px);
opacity: 1;
}
}
#-moz-keyframes MenuAnimIn2 {
0% {
-moz-transform: translateX(-100%);
opacity: 0;
}
100% {
-moz-transform: translateX(0px);
opacity: 1;
}
}
#keyframes MenuAnimIn2 {
0% {
transform: translateX(-100%);
opacity: 0;
}
100% {
transform: translateX(0px);
opacity: 1;
}
}
You have to use the plugin like this : with animationClasses "in" and "out" not "classin" and "classout"
$(function() {
$( '#dl-menu' ).dlmenu({
animationClasses : { in : 'dl-animate-in-2', out : 'dl-animate-out-2' }
});
});

Seamlessly transition back and forth with only one animation class?

I want to use one class to trigger an animation, and upon removal of that class redo that animation in reverse.
It's hard to visualize, so I've created a CodePen of where I'm at currently.
You'll notice that when .zoom is removed from #box, the #box just vanishes. It doesn't do the animation in reverse, which is ultimately the goal.
How can I seamlessly transition back and forth, with only one animation class? Normally I might use transitions, but you can't transition with transforms.
Try adding .zoomout class , css animations , utilizing .removeClass() , second class at .toggleClass()
window.onclick = function() {
if (!$("#box").is(".zoom")) {
$("#box").removeClass("zoomout")
.toggleClass("zoom");
} else {
$("#box").toggleClass("zoom zoomout");
}
};
#box {
width: 256px;
height: 256px;
background: black;
opacity: 0;
display: block;
transform: scale(1.15, 1.15);
margin: 16px 0px;
}
.zoom {
animation: zoom 500ms;
animation-fill-mode: both;
-moz-animation: zoom 500ms;
-moz-animation-fill-mode: both;
-webkit-animation: zoom 500ms;
-webkit-animation-fill-mode: both;
}
.zoomout {
animation: zoomout 500ms;
animation-fill-mode: both;
-moz-animation: zoomout 500ms;
-moz-animation-fill-mode: both;
-webkit-animation: zoomout 500ms;
-webkit-animation-fill-mode: both;
}
#keyframes zoom {
0% {
opacity: 0;
transform: scale(1.15);
}
100% {
opacity: 1;
transform: scale(1);
}
}
#-moz-keyframes zoom {
0% {
opacity: 0;
transform: scale(1.15);
}
100% {
opacity: 1;
transform: scale(1);
}
}
#-webkit-keyframes zoom {
0% {
opacity: 0;
transform: scale(1.15);
}
100% {
opacity: 1;
transform: scale(1);
}
}
#keyframes zoomout {
0% {
opacity: 1;
transform: scale(1.15);
}
100% {
opacity: 0;
transform: scale(1);
}
}
#-moz-keyframes zoomout {
0% {
opacity: 1;
transform: scale(1.15);
}
100% {
opacity: 0;
transform: scale(1);
}
}
#-webkit-keyframes zoomout {
0% {
opacity: 1;
transform: scale(1.15);
}
100% {
opacity: 0;
transform: scale(1);
}
}
body {
margin: 0;
text-align: center;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -60%);
-moz-transform: translate(-50%, -60%);
-webkit-transform: translate(-50%, -60%);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<div id="box"></div>
Click the document to toggle the box.
codepen http://codepen.io/anon/pen/vOxxKE

css3 transition start on click

I want a CSS3 transition to start after click.
Now it works fine if the element gets added a class with jQuery (see span.toggle-nav.two) which knows then what to do.
I've tried with :focus (see span.toggle-nav.one) but that doesn't work. How can I make it work without jQuery?
Please have a look here: http://jsfiddle.net/aE4C7/ clicking on Two works but clicking on One does not.
<span class="toggle-nav one">One</span>
<span class="toggle-nav two">Two</span>
<script type="text/javascript">
$('.toggle-nav.two').on('click',function(){
$(this).addClass("click");
});
</script>
<style type="text/css">
.toggle-nav {
background-image:url(https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcS8hRiDDs6RJRzelpuFRX2wG5Wx2cQPOBWKYCOmlA2Wr34dx1vv);
background-repeat:no-repeat;
width:50px;height:50px;
display:inline-block;
}
.toggle-nav.one:focus {
-webkit-animation: spin 0.6s infinite linear;
-moz-animation: spin 0.6s infinite linear;
-o-animation: spin 0.6s infinite linear;
-ms-animation: spin 0.6s infinite linear;
}
.toggle-nav.two.click {
-webkit-animation: spin 0.6s infinite linear;
-moz-animation: spin 0.6s infinite linear;
-o-animation: spin 0.6s infinite linear;
-ms-animation: spin 0.6s infinite linear;
}
#-webkit-keyframes spin {
0% { -webkit-transform: rotate(0deg);}
100% { -webkit-transform: rotate(180deg);}
}
#-moz-keyframes spin {
0% { -moz-transform: rotate(0deg);}
100% { -moz-transform: rotate(180deg);}
}
#-o-keyframes spin {
0% { -o-transform: rotate(0deg);}
100% { -o-transform: rotate(180deg);}
}
#-ms-keyframes spin {
0% { -ms-transform: rotate(0deg);}
100% { -ms-transform: rotate(180deg);}
}
</style>
Is there a way to make this work without jQuery?
To let span getting focus, you need to set tabindex attribute:
<span class="toggle-nav one" tabindex="-1">One</span>
Then you could wish for styling to set CSS outline property too:
outline: none;
DEMO
You can actually do this using purely CSS - The only way to correctly simulate click events in CSS is to fake it with a checkbox, otherwise using :active or :focus will stop any applied transition or animation as soon as the element loses focus, not when it is clicked on again.
Demo Fiddle
HTML
<div>
<input id='box' type='checkbox' />
<label for='box'>Click Me!</label>
</div>
CSS
div {
position:relative;
}
label {
position:absolute;
left:0;
background:white;
}
input[type=checkbox] {
opacity:0;
}
input[type=checkbox]:checked + label {
-webkit-animation: spin 0.6s infinite linear;
-moz-animation: spin 0.6s infinite linear;
-o-animation: spin 0.6s infinite linear;
-ms-animation: spin 0.6s infinite linear;
}
#-webkit-keyframes spin {
0% {
-webkit-transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(180deg);
}
}
#-moz-keyframes spin {
0% {
-moz-transform: rotate(0deg);
}
100% {
-moz-transform: rotate(180deg);
}
}
#-o-keyframes spin {
0% {
-o-transform: rotate(0deg);
}
100% {
-o-transform: rotate(180deg);
}
}
#-ms-keyframes spin {
0% {
-ms-transform: rotate(0deg);
}
100% {
-ms-transform: rotate(180deg);
}
}

Categories