Restart animation in CSS3: any better way than removing the element?
Just set the animation
property via JavaScript to "none"
and then set a timeout that changes the property to ""
, so it inherits from the CSS again.
Demo for Webkit here: http://jsfiddle.net/leaverou/xK6sa/
However, keep in mind that in real world usage, you should also include -moz- (at least).
Restart CSS3 animation using Javascript
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>
CSS animation doesn't restart when resetting class
I think I figured it out. According to this, css animation can't get applied to the same node twice (even if you have a different animation!). So I had to clone the node, remove the original, and add back the cloned node.
Restart CSS animation on the same element
When you bind event handler on div as well as on images inside the div, it will be called twice as there is no e.preventBubble()
in event handler. You can avoid this by using it only on the div.
Second issue is that after first click inside the div, the transition is in final state and you don't move it to initial state. I would achieve required behavior by using 2 classes. One for transition and one for initial state, final state is implicit here, opacity:1
is default value.
.pantalla.invisible {
opacity: 0;
}
.pantalla.horizTranslateApareix {
-webkit-transition: 1s;
-moz-transition: 1s;
-ms-transition: 1s;
-o-transition: 1s;
transition: 1s;
}
Main part is in JS. We start by removing the transition, otherwise it would took 1s to hide the image as well. Then we hide the image and return the transition, do image swapping and finally show the image again, starting the transition.
function canviaImatge()
{
img2.classList.remove('horizTranslateApareix');
img2.classList.add('invisible');
img2.offsetHeight; // <-- force repaint, otherwise browser optimize and nothing changes
img2.classList.add('horizTranslateApareix');
// image swapping
img2.classList.remove('invisible');
}
This would be the ideal case, but browsers optimize, so we can't use it as simply as that. Browsers do as much as possible without repainting the page, so they merge several opearions to one and we loose our functionality. That's where magic comes in place. We enforce repaint asking for img2.offsetHeight
, which has to recalculate positions and repaint the relevant part of page (possibly whole page). Other ways to achieve it, is to move code to setTimeout
function, which can't be optimized either.
setTimeout(function() {
img2.classList.add('horizTranslateApareix');
img2.classList.remove('invisible');
}, 1)
Demo at http://jsfiddle.net/Gobie/e4m3R/2/
How do I re-trigger a WebKit CSS animation via JavaScript?
I found the answer based on the source code and examples at the CSS3 transition tests github page.
Basically, CSS animations have an animationEnd
event that is fired when the animation completes.
For webkit browsers this event is named “webkitAnimationEnd
”. So, in order to reset an animation after it has been called you need to add an event-listener to the element for the animationEnd
event.
In plain vanilla javascript:
var element = document.getElementById('box');
element.addEventListener('webkitAnimationEnd', function(){
this.style.webkitAnimationName = '';
}, false);
document.getElementById('button').onclick = function(){
element.style.webkitAnimationName = 'shake';
// you'll probably want to preventDefault here.
};
and with jQuery:
var $element = $('#box').bind('webkitAnimationEnd', function(){
this.style.webkitAnimationName = '';
});
$('#button').click(function(){
$element.css('webkitAnimationName', 'shake');
// you'll probably want to preventDefault here.
});
The source code for CSS3 transition tests (mentioned above) has the following support
object which may be helpful for cross-browser CSS transitions, transforms, and animations.
Here is the support code (re-formatted):
var css3AnimationSupport = (function(){
var div = document.createElement('div'),
divStyle = div.style,
// you'll probably be better off using a `switch` instead of theses ternary ops
support = {
transition:
divStyle.MozTransition === ''? {name: 'MozTransition' , end: 'transitionend'} :
// Will ms add a prefix to the transitionend event?
(divStyle.MsTransition === ''? {name: 'MsTransition' , end: 'msTransitionend'} :
(divStyle.WebkitTransition === ''? {name: 'WebkitTransition', end: 'webkitTransitionEnd'} :
(divStyle.OTransition === ''? {name: 'OTransition' , end: 'oTransitionEnd'} :
(divStyle.transition === ''? {name: 'transition' , end: 'transitionend'} :
false)))),
transform:
divStyle.MozTransform === '' ? 'MozTransform' :
(divStyle.MsTransform === '' ? 'MsTransform' :
(divStyle.WebkitTransform === '' ? 'WebkitTransform' :
(divStyle.OTransform === '' ? 'OTransform' :
(divStyle.transform === '' ? 'transform' :
false))))
//, animation: ...
};
support.transformProp = support.transform.name.replace(/([A-Z])/g, '-$1').toLowerCase();
return support;
}());
I have not added the code to detect “animation” properties for each browser. I’ve made this answer “community wiki” and leave that to you. :-)
Reuse CSS animation in reversed direction (by resetting the state?)
No, there is no way to restart the animation using CSS alone. You'd have to use JavaScript to remove the animation from the element and then re-apply it to the element (after a delay) for it to restart.
The below is what the W3C's CSS3 Animation Spec says (in a different context, but the point should hold good for this case also):
Note also that changing the value of ‘animation-name’ does not necessarily restart an animation (e.g., if a list of animations are applied and one is removed from the list, only that animation will stop; The other animations will continue). In order to restart an animation, it must be removed then reapplied.
emphasis is mine
This CSS Tricks Article by Chris Coiyer also indicates the same and provides some JS solutions for restarting an animation. (Note: The article has a reference to Oli's dabblet which claims that altering properties like duration, iteration count makes it restart on Webkit but it seems to be outdated as they no longer work on Chrome).
Summary:
While you have already touched upon the following, I am going to re-iterate for completeness sake:
- Once an animation is applied on the element, it remains on the element until it is removed.
- UA does keep track of the animation being on the element and whether it has completed or not.
- When you apply the same animation on
:checked
(albeit with a different direction), the UA does nothing because the animation already exists on the element. - The switch of positions (instantaneous) while clicking the checkbox is because of the
transform
that is applied within the:checked
selector. The animation's presence makes no difference.
Solutions:
As you can see from the below snippet, achieving this with a single animation is pretty complex even when using JavaScript.
var input = document.getElementsByClassName("my-checkbox")[0];
input.addEventListener('click', function() { if (this.checked) { this.classList.remove('my-checkbox'); window.setTimeout(function() { input.classList.add('anim'); input.classList.add('checked'); }, 10); } else { this.classList.remove('anim'); window.setTimeout(function() { input.classList.remove('checked'); input.classList.add('my-checkbox'); }, 10); }});
input { transform: translate3d(50px, 0, 0);}.my-checkbox { animation: moveLeft 1s; animation-direction: reverse;}.checked { transform: translate3d(0px, 0, 0);}.anim{ animation: moveLeft 1s;}@keyframes moveLeft { from { transform: translate3d(50px, 0, 0); } to { transform: translate3d(0px, 0, 0); }}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script><input type="checkbox" class="my-checkbox">
Restart CSS3 Animation without javascript?
Unfortunately it's not possible to set a delay before each animation, but you can set a delay inside the animation. Just let the animation do nothing for a while until you reach a certain percentage.
Here's the updated code.
@keyFrames scale {
90% {
transform: scale(1)
}
95% {
transform: scale(1.3)
}
100% {
transform: scale(1);
}
}
.animated-btn {
display: inline-block;
animation: scale ease-in 1;
animation-fill-mode: forwards;
animation-duration: 12.4s;
animation-delay: 0s;
animation-iteration-count: infinite;
/* Or the shorthand:
animation: scale 1.4s 0s infinite ease-in forwards;
*/
}
Related Topics
Difference Between the Different Methods of Putting JavaScript Code in an ≪A≫
Stop User from Using "Print Scrn"/"Printscreen" Key of the Keyboard For Any Web Page
Getting Binary (Base64) Data from Html5 Canvas (Readasbinarystring)
Bootstrap Navbar Active State Not Working
How to Use External ".Js" Files
How to Escape Quotes in HTML Attribute Values
Why Should Y.Innerhtml = X.Innerhtml; Be Avoided
Best Way to Obfuscate an E-Mail Address on a Website
How to Do Fade-In and Fade-Out With JavaScript and Css
How to Change/Remove CSS Classes Definitions At Runtime
How to Have Content from an Iframe Overflow Onto the Parent Frame
How to Select All Checkboxes With Jquery
How to Invoke Objective-C Method from JavaScript and Send Back Data to JavaScript in Ios
What Do Queryselectorall and Getelementsby* Methods Return
How to Merge Properties of Two JavaScript Objects Dynamically