I have few elements I need to slide, but I don't want to attach whole jQ lib. I like jQ a lot, but whole lib is just overkill in this example.
How to convert jq slideUp/slideDown/toggle to vanilla JS with support of multiple elements passed to function?
JQ code:
var $context = getContext(context);
$($context).on('click', '.menu', function () {
$('.nav').slideToggle();
});
JS code:
var list = document.getElementsByClassName("class1", "class2", "class3");
//or
var list = document.querySelectorAll("class1", "class2", "class3");
var slideUp = function(targets, duration){
// execution
};
slideUp(list, 500);
SO wizards make it happen! :)
I wasn't happy with the last solution I gave you it was rushed and buggy totally unacceptable, Hope you can forgive me...so this is a better version with the clicks of each item working too
const clicker = document.getElementsByClassName("clicker")[0];
clicker.addEventListener("click", function() {
process(document.querySelectorAll(".js-toggle"));
});
[...document.querySelectorAll(".js-toggle")].forEach((element) =>
element.addEventListener("click", function() {
process(this)
})
)
const container = [];
function process(linkToggle) {
container.length = 0
if (linkToggle.length > 0) {
for (let i = 0; i < linkToggle.length; i++) {
container.push(
document.getElementById(linkToggle[i].dataset.container))
animate(container[i])
}
} else {
container.push(
document.getElementById(linkToggle.dataset.container))
animate(container[0])
}
}
function animate(element) {
if (!element.classList.contains("active")) {
element.classList.add("active");
element.style.height = "auto";
let height = parseInt(element.clientHeight || 0)
element.style.height = "0px";
setTimeout(function() {
for (let t = 0; t < container.length; t++) {
do {
container[t].style.height =
parseInt(container[t].style.height || height) +
1 + 'px'
} while (parseInt(container[t].style.height || height) < height);
}
}, 0);
} else {
element.style.height = "0px";
element.addEventListener(
"transitionend",
function() {
element.classList.remove("active");
}, {
once: true
}
);
}
}
.clicker {
cursor: pointer;
background: red;
}
.box {
width: 300px;
border: 1px solid #000;
margin: 10px;
cursor: pointer;
}
.toggle-container {
transition: height 0.35s ease-in-out;
overflow: hidden;
}
.toggle-container:not(.active) {
display: none;
}
<div class="clicker">CLICK ME</div>
<div class="box">
<div class="js-toggle" data-container="toggle-1">Click1</div>
<div class="toggle-container" id="toggle-1">I have an accordion and am animating the the height for a show reveal - the issue is the height which i need to set to auto as the information is different lengths.<br><br> I have an accordion and am animating the the height fferent lengths.
</div>
</div>
<div class="box">
<div class="js-toggle" data-container="toggle-2">Click2</div>
<div class="toggle-container open" id="toggle-2">I have an accordion and am animating the the height for a show reveal - the issue is the height which i need to set to auto as the information is different lengths.<br><br> I have an accordion and am animating the the height fferent lengths.
</div>
</div>
<div class="box">
<div class="js-toggle" data-container="toggle-3">Click3</div>
<div class="toggle-container" id="toggle-3">I have an accordion and am animating the the height for a show reveal - the issue is the height which i need to set to auto as the information is different lengths.<br><br> I have an accordion and am animating the the height fferent lengths.
</div>
</div>
I hope this helps
you could just use css like so ( wasn't sure witch way you wanted to slid but this gives you an idea of how to do it):
var $slider = document.getElementById('slider');
var $toggle = document.getElementById('toggle');
$toggle.addEventListener('click', function() {
var isOpen = $slider.classList.contains('slide-in');
$slider.setAttribute('class', isOpen ? 'slide-out' : 'slide-in');
});
#slider {
position: absolute;
width: 100px;
height: 100px;
background: blue;
transform: translateX(-100%);
-webkit-transform: translateX(-100%);
}
.slide-in {
animation: slide-in 0.5s forwards;
-webkit-animation: slide-in 0.5s forwards;
}
.slide-out {
animation: slide-out 0.5s forwards;
-webkit-animation: slide-out 0.5s forwards;
}
#keyframes slide-in {
100% {
transform: translateX(0%);
}
}
#-webkit-keyframes slide-in {
100% {
-webkit-transform: translateX(0%);
}
}
#keyframes slide-out {
0% {
transform: translateX(0%);
}
100% {
transform: translateX(-100%);
}
}
#-webkit-keyframes slide-out {
0% {
-webkit-transform: translateX(0%);
}
100% {
-webkit-transform: translateX(-100%);
}
}
<div id="slider" class="slide-in">
<ul>
<li>Lorem</li>
<li>Ipsum</li>
<li>Dolor</li>
</ul>
</div>
<button id="toggle" style="position:absolute; top: 120px;">Toggle</button>
I can't take credit for this its lifted from:
CSS 3 slide-in from left transition
I hope this helps
Could you not simply include the css in the page header so wouldn't need to edit any style sheets, well in any case then how about this:
function SlideDown() {
const element = document.getElementById("slider");
let top = 0;
const up = setInterval(MoveDown, 10);
function MoveDown() {
if (top == 50) {
clearInterval(up);
} else {
top++;
element.style.top = top + '%';
}
}
}
function SlideUp() {
const element = document.getElementById("slider");
let top = parseInt(element.style.top);
const down = setInterval(MoveUp, 10);
function MoveUp() {
if (top == -100) {
clearInterval(down);
} else {
top--;
element.style.top = top + '%';
}
}
}
<!DOCTYPE html>
<html>
<body>
<div id="slider" style="position:absolute; top: -100px;">
<ul>
<li>Lorem</li>
<li>Ipsum</li>
<li>Dolor</li>
</ul>
</div>
<button onclick="SlideDown()">Slide Down</button>
<button onclick="SlideUp()">Slide Up</button>
</body>
</html>
I hope this helps
Related
jQuery(function ($) {
var target = $("#target");
target.html(target.text().replace(/./g, "<span>$&</span>"));
setTimeout(runAnimation, 250);
function runAnimation() {
var index, spans;
index = 0;
spans = target.children();
doOne();
function doOne() {
var span = $(spans[index]);
if (!$.trim(span.text())) {
// Skip blanks
next();
return;
}
// Do this one
span.css({
position: "relative",
})
.animate(
{
top: "-20",
},
"fast"
)
.animate(
{
top: "0",
},
"fast",
function () {
span.css("position", "");
next();
}
);
}
function next() {
++index;
if (index < spans.length) {
doOne();
} else {
setTimeout(runAnimation, 500);
}
}
}
});
.title {
margin: auto;
width: 50%;
color: black;
text-align: right;
}
#target:hover {
color: rgb(21, 121, 252);
animation-name: bounce;
animation-duration: 2s;
}
#keyframes bounce {
0% { transform: translateY(0); }
50% { transform: translateY(-50px); }
100% { transform: translateY(0); }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="title">
<p style="font-size: 45px;"><span id="target">I</span><span id="target">'</span><span id="target">m</span><span>
</span><span id="target">K</span><span id="target">r</span><span id="target">i</span><span id="target">s</span>
</p>
</div>
I'm trying to add a wobble effect on each letter but I can't get it to work, I would like the letters to get a bit bigger while hovering them and making the effect run. I'm just learning javascript so I'm not really good at it, the snippet doesn't work and I don't know what's the problem with it.
I found this code for the wobble effect but it's not working, can someone help ? Thanks
Instead of manually typing the letters in individual span blocks, let JavaScript do it. This will be much more flexible.
Other than that, you do not need to use JavaScript for the animation, do it with CSS instead. That will be much simpler and handleable.
const animatedElements = document.getElementsByClassName('animate');
[...animatedElements].forEach(elm => {
let text = elm.innerText.split(''); // Split the text into letters and store them in an array
elm.innerText = ''; // Clear the text in the div
// Add the letters one by one, this time inside a <span>
text.forEach(letter => {
const span = document.createElement('span');
span.innerText = letter;
elm.appendChild(span);
})
})
.animate>span {
display: inline-block; /* Changing display from the default `inline` to `inline-block` so that `transform` rules apply */
white-space: break-spaces; /* This is necessary so that the `inline-block` does not collapse the "spaces" */
transition: transform 200ms ease-in-out;
}
.animate>span:hover {
transform: translateY(-10px);
}
/* The following rules are just to format the embedded result */
.animate {
margin: 40px;
font-size: 40px;
}
<div class="animate">
I'm Kris
</div>
If anyone can phrase this question better than I can, please advise and I will alter (or edit yourself).
Here's my current jsfiddle: https://jsfiddle.net/5v7mzadu/
My HTML:
<div class="text-cycler">
WE <div class="c-text" id="ctext-1">CARE</div>
<div class="c-text" id="ctext-2">THINK</div>
<div class="c-text" id="ctext-3">SEE</div>
<div class="c-text" id="ctext-1">KNOW</div>
</div>
My CSS:
.text-cycler {
text-align:center;
font-size:25px;
}
.c-text {
display:inline-block
}
My Javascript:
var divs = $('div[id^="ctext-"]').hide(),
i = 0;
(function cycle() {
divs.eq(i).fadeIn(400)
.delay(1000)
.fadeOut(400, cycle);
i = ++i % divs.length;
})();
As you can see the second word fades in/out,. I'd like to add a smooth transition to the div, so that the width of the div container does NOT abruptly change width size. (so that the width "snap" is more smooth)
Can anyone help?
I believe you needed the animation over the content and text alignment center.
And indeed this must solve your purpose.
I have added span{white-space: nowrap; vertical-align: text-top;} to force it to align in single line, and added jQuery animate method to animate the width of the rotating text
And here's the fiddle for you to play around
var divs = $('div[id^="ctext-"]').hide(),
i = 0;
(function cycle() {
divs.eq(i)
.animate(400, function() {
$('.x').animate({
width: $(this).innerWidth()
});
})
.fadeIn(400)
.delay(1000)
.fadeOut(400, cycle);
i = ++i % divs.length;
})();
.text-cycler {
text-align: center;
font-size: 25px;
}
span {
white-space: nowrap;
vertical-align: text-top;
}
.c-text {
display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="text-cycler">
<span> WE </span>
<span class="x">
<div class="c-text" id="ctext-1">CARE</div>
<div class="c-text" id="ctext-2">THINK</div>
<div class="c-text" id="ctext-3">SEE</div>
<div class="c-text" id="ctext-1">KNOW</div>
</span>
</div>
See this snippet
var divs = $('div[id^="ctext-"]').hide(),
i = 0;
(function cycle() {
divs.eq(i).fadeIn(400)
.delay(1000)
.fadeOut(400, cycle);
i = ++i % divs.length;
})();
.text-cycler {
font-size:25px;
position:fixed; /*added*/
padding-left:40% /*added*/
}
.c-text {
display:inline-block
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="text-cycler" align="center">
WE <div class="c-text" id="ctext-1">CARE</div><div class="c-text" id="ctext-2">THINK</div><div class="c-text" id="ctext-3">SEE</div><div class="c-text" id="ctext-1">KNOW</div>
</div>
JavascriptLess way.
If you want to get funky. (No seriously, this is more a funky solution than usable)
.text-cycler {
width:75%;
margin:auto;
user-select: none;
text-align:center;
font-size:5vw;
}
.text-cycler:after {
content:"";
display:inline-block;
animation: change;
animation-duration: 10s;
animation-iteration-count: infinite;
}
#keyframes change {
0% {
content: "CARE";
opacity: 0;
}
3% {
opacity: 1;
}
22% {
opacity: 1;
}
25% {
content: "CARE";
opacity: 0;
}
25.1% {
content: "THINK";
}
28% {
opacity: 1;
}
47% {
opacity: 1;
}
50% {
content: "THINK";
opacity: 0;
}
50.1% {
content: "SEE";
}
53% {
opacity: 1;
}
72% {
opacity: 1;
}
75% {
content: "SEE";
opacity: 0;
}
75.1% {
content: "KNOW";
}
78% {
opacity: 1;
}
97% {
opacity: 1;
}
100% {
content: "KNOW";
opacity: 0;
}
}
<div class="text-cycler">
WE
</div>
First: I'm sorry in advance for my english. This is not my first language. :)
The Situation
So, this is the deal: I'm trying to make a single button where the user can click and then it will automatically scroll down to the next DIV. Each DIV's have the class .anchor, and the one that is "selected" have another class called .anchor--selected. When you arrive at the last one, the arrow rotate to 180deg, so the user can see it will go all the way up. Yay! This part is working!
And the great part is: I don't have to give any of my div a name, since I don't know how many there will be.
But, the next part it's kind of tricky... I mean, for someone who doesn't work a lot with jQuery. (I'm learning, slowly, but I'm learning!)
The Problem
Now, when I'm in the middle of the page while scrolling and I decide instead to click, it go all the way up to the page. So, I tried a little something, and it seem to work. But when I'm in the last anchor, and I scroll too much, it giving me this error Uncaught TypeError: Cannot read property 'top' of undefined(…).
The CodePen
So here the link to the not so working anchor button with scrolling.
$(document).ready(function(){
$(".scroll-down-arrow").on("click", function(e) {
e.preventDefault();
var currentAnchor = $(".anchor--selected");;
var nextAnchor = currentAnchor.next(".anchor");
var firstAnchor = $(".anchor").first();
var lastAnchor = $(".anchor").last();
if(currentAnchor.is(lastAnchor)) {
currentAnchor.removeClass("anchor--selected");
firstAnchor.addClass("anchor--selected");
$('html, body').stop().animate({scrollTop:firstAnchor.offset().top});
$(this).removeClass("prev").addClass("next");
} else {
currentAnchor.removeClass("anchor--selected");
nextAnchor.addClass("anchor--selected");
$('html, body').stop().animate({scrollTop:nextAnchor.offset().top});
if(currentAnchor.is(lastAnchor.prev())) {
$(this).removeClass("next").addClass("prev");
}
}
});
$(window).on("scroll", function() {
var scrollPos = $(window).scrollTop();
var currentAnchor = $(".anchor--selected");;
var nextAnchor = currentAnchor.next(".anchor");
var prevAnchor = currentAnchor.prev(".anchor");
var firstAnchor = $(".anchor").first();
var lastAnchor = $(".anchor").last();
console.log("scrollPos : " + scrollPos + " currentAnchor : " + nextAnchor.offset().top);
console.log(scrollPos <= nextAnchor.offset().top);
console.log("Current anchor is last? : " + currentAnchor.is(lastAnchor));
if(scrollPos >= nextAnchor.offset().top) {
if(currentAnchor.is(lastAnchor)) {
currentAnchor.removeClass("anchor--selected");
prevAnchor.addClass("anchor--selected");
$(".scroll-down-arrow").removeClass("prev").addClass("next");
} else {
currentAnchor.removeClass("anchor--selected");
nextAnchor.addClass("anchor--selected");
if(currentAnchor.is(firstAnchor)) {
$(".scroll-down-arrow").removeClass("next").addClass("prev");
}
}
}
});
});
#one, #two, #three, #four, #five {
padding: 15px;
}
#one {
height: 500px;
background-color: #f0f8ff;
}
#two {
height: 300px;
background-color: #7fffd4;
}
#three {
height: 150px;
background-color: #deb887;
}
#four {
height: 600px;
background-color: #5f9ea0;
}
#five {
height: 1000px;
background-color: #f3b9c6;
}
.scroll-down-arrow {
width: 50px;
height: 50px;
border-radius: 50%;
background-color: #010101;
position: fixed;
bottom: 25px;
right: 25px;
cursor: pointer;
-webkit-transition: all 250ms ease-in-out;
-moz-transition: all 250ms ease-in-out;
-o-transition: all 250ms ease-in-out;
transition: all 250ms ease-in-out;
}
.scroll-down-arrow.prev {
-webkit-transform: rotate(180deg);
-ms-transform: rotate(180deg);
-o-transform: rotate(180deg);
transform: rotate(180deg);
}
.scroll-down-arrow.next {
-webkit-transform: rotate(0deg);
-ms-transform: rotate(0deg);
-o-transform: rotate(0deg);
transform: rotate(0deg);
}
.scroll-down-arrow i {
color: #f1f1f1;
font-size: 24px;
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
-moz-transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
-o-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<main>
<div id="one" class="anchor anchor--selected">
This is my first div
</div>
<div id="two" class="anchor">
This is my second div
</div>
<div id="three" class="anchor">
This is my third div
</div>
<div id="four" class="anchor">
This is my fourth div
</div>
<div id="five" class="anchor">
This is my fifth div
</div>
<div class="scroll-down-arrow next"><i class="fa fa-arrow-down" aria-hidden="true"></i></div>
</main>
Conclusion
So, I've tried to reuse my code on the "scroll click" and put it on the "window scroll". But I think I'm missing something and I would like some help to get throught it.
Thank you very much and feel free to ask questions! :)
Since you aren't testing to see if there is another .anchor, jQuery is throwing an error. Just test to see if there is a next .anchor.
JQUERY
$(document).ready(function(){
$(".scroll-down-arrow").on("click", function(e) {
e.preventDefault();
var currentAnchor = $(".anchor--selected");;
var nextAnchor = currentAnchor.next(".anchor");
var firstAnchor = $(".anchor").first();
var lastAnchor = $(".anchor").last();
if(currentAnchor.is(lastAnchor)) {
currentAnchor.removeClass("anchor--selected");
firstAnchor.addClass("anchor--selected");
$('html, body').stop().animate({scrollTop:firstAnchor.offset().top});
$(this).removeClass("prev").addClass("next");
} else {
currentAnchor.removeClass("anchor--selected");
nextAnchor.addClass("anchor--selected");
$('html, body').stop().animate({scrollTop:nextAnchor.offset().top});
if(currentAnchor.is(lastAnchor.prev())) {
$(this).removeClass("next").addClass("prev");
}
}
});
$(window).on("scroll", function() {
var scrollPos = $(window).scrollTop();
var currentAnchor = $(".anchor--selected");
if(currentAnchor.next(".anchor").length){
var nextAnchor = currentAnchor.next(".anchor");
} else {
var nextAnchor = $(".anchor:first");
}
var prevAnchor = currentAnchor.prev(".anchor");
var firstAnchor = $(".anchor").first();
var lastAnchor = $(".anchor").last();
console.log("scrollPos : " + scrollPos + " currentAnchor : " + nextAnchor.offset().top);
console.log(scrollPos <= nextAnchor.offset().top);
console.log("Current anchor is last? : " + currentAnchor.is(lastAnchor));
if(scrollPos >= nextAnchor.offset().top) {
if(currentAnchor.is(lastAnchor)) {
currentAnchor.removeClass("anchor--selected");
prevAnchor.addClass("anchor--selected");
$(".scroll-down-arrow").removeClass("prev").addClass("next");
} else {
currentAnchor.removeClass("anchor--selected");
nextAnchor.addClass("anchor--selected");
if(currentAnchor.is(firstAnchor)) {
$(".scroll-down-arrow").removeClass("next").addClass("prev");
}
}
}
});
});
Fiddle: https://jsfiddle.net/yak613/up6rLqou/
Note: This doesn't work when scrolling up, I will attempt to fix that.
I recently came across GotoMeeting's website and I was very taken with the animated footer that slides away after you scroll down a bit. I wanted to re-create it myself and I mostly have it working. Here is my fiddle. The issue I have is that when you scroll up it 'snaps' into place rather than animating back up. What can I do to fix that?
Here is my code as well.
<html>
<head>
<style>
body {
width:100%;
height:1600px;
margin:0;
}
#bar {
position:fixed;
bottom:0;
width:100%;
height:100px;
background-color:gray;
}
#-webkit-keyframes slideout {
0% {
-webkit-transform:translateY(0);
transform:translateY(0);
}
100% {
visibility:hidden;
-webkit-transform:translateY(100%);
transform:translateY(100%);
}
}
#keyframes slideout {
0% {
-webkit-transform:translateY(0);
transform:translateY(0);
}
100% {
visibility:hidden;
-webkit-transform:translateY(100%);
transform:translateY(100%);
}
}
.slide-down {
-webkit-animation-duration:3s;
-webkit-animation-fill-mode:both;
-webkit-animation-name:slideout;
animation-duration:3s;
animation-fill-mode:both;
animation-name:slideout;
}
#-webkit-keyframes slidein {
0% {
visibility:visible;
-webkit-transform:translateY(-100%);
transform:translateY(-100%);
}
100% {
-webkit-transform:translateY(0);
transform:translateY(0);
}
}
#keyframes slidein {
0% {
visibility:visible;
-webkit-transform:translateY(-100%);
transform:translateY(-100%);
}
100% {
-webkit-transform:translateY(0);
transform:translateY(0);
}
}
.slide-up {
-webkit-animation-duration:6s;
-webkit-animation-fill-mode:both: -webkit-animation-name:slidein;
animation-duration:6s;
animation-fill-mode:both: animation-name:slidein;
}
</style>
<script type="text/javascript">
function onScrollBody() {
var doc = document.documentElement;
var top = (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0);
document.getElementById("scrollinfo").innerHTML = top;
if (top > 200) document.getElementById("bar").className = "slide-down";
else if (top < 200) document.getElementById("bar").className = "slide-up";
}
</script>
</head>
<body onscroll="onScrollBody()">
<div id="bar">
<p>TRY FOR FREE</p>
<p id="scrollinfo"></p>
</div>
</body>
</html>
Since you're just animating a single property from 0% to 100%, I would simply recommend using transition which will automatically animate a property when it changes its value. That way, you simply need to add/remove a single CSS class that sets a new value and the change will animate as you want it to.
I updated so you can see what I mean:
window.onscroll = onScrollBody;
function onScrollBody() {
var doc = document.documentElement;
var top = (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0);
document.getElementById("scrollinfo").innerHTML = top;
if (top > 200) document.getElementById("bar").className = "slide-down";
else if (top < 200) document.getElementById("bar").className = "";
//var nYScroll = document.body.scrollTop;
//document.getElementById("scrollinfo").innerHTML = nYScroll;
//if (nYScroll > 200) document.getElementById("bar").className = "slide-down";
//else if (nYScroll < 200) document.getElementById("bar").className = "slide-up";
}
body {
width:100%;
height:1600px;
margin:0;
}
#bar {
position:fixed;
bottom:0;
width:100%;
height:100px;
background-color:gray;
transition: transform 1s ease-out;
-webkit-transition: transform 1s ease-out;
}
.slide-down {
-webkit-transform:translateY(100%);
transform:translateY(100%);
}
<body onscroll="onScrollBody()">
<div id="bar">
<p>TRY FOR FREE</p>
<p id="scrollinfo"></p>
</div>
</body>
So, I've got this -webkit-animation rule:
#-webkit-keyframes shake {
0% {
left: 0;
}
25% {
left: 12px;
}
50% {
left: 0;
}
75% {
left: -12px;
}
100% {
left:0;
}
}
And some CSS defining some of the animation rules on my box:
#box{
-webkit-animation-duration: .02s;
-webkit-animation-iteration-count: 10;
-webkit-animation-timing-function: linear;
}
I can shake the #box like this:
document.getElementById("box").style.webkitAnimationName = "shake";
But I can't shake it again later.
This only shakes the box once:
someElem.onclick = function(){
document.getElementById("box").style.webkitAnimationName = "shake";
}
How can I re-trigger a CSS animation via JavaScript without using timeouts or multiple animations?
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. :-)
You have to first remove the animation, then add it again. Eg:
document.getElementById("box").style.webkitAnimationName = "";
setTimeout(function ()
{
document.getElementById("box").style.webkitAnimationName = "shake";
}, 0);
To do this without setTimeout remove the animation during onmousedown, and add it during onclick:
someElem.onmousedown = function()
{
document.getElementById("box").style.webkitAnimationName = "";
}
someElem.onclick = function()
{
document.getElementById("box").style.webkitAnimationName = "shake";
}
Following the suggestion from https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Tips, remove and then add the animation class, using requestAnimationFrame to ensure that the rendering engine processes both changes. I think this is cleaner than using setTimeout, and handles replaying an animation before the previous play has completed.
$('#shake-the-box').click(function(){
$('#box').removeClass("trigger");
window.requestAnimationFrame(function(time) {
window.requestAnimationFrame(function(time) {
$('#box').addClass("trigger");
});
});
});
http://jsfiddle.net/gcmwyr14/5/
A simple but effective alternative:
HTML:
<div id="box"></div>
<button id="shake-the-box">Shake it!</button>
css:
#box{
background: blue;
margin:30px;
height:50px;
width:50px;
position:relative;
-moz-animation:shake .2s 0 linear 1;
-webkit-animation:shake .2s 0 linear 1;
}
#box.trigger{
display:table;
}
#-webkit-keyframes shake {
0% {
left: 0;
}
25% {
left: 12px;
}
50% {
left: 0;
}
75% {
left: -12px;
}
100% {
left:0;
}
}
#-moz-keyframes shake {
0% {
left: 0;
}
25% {
left: 12px;
}
50% {
left: 0;
}
75% {
left: -12px;
}
100% {
left:0;
}
}
jQuery:
$('#shake-the-box').click(function(){
$('#box').toggleClass('trigger');
});
Demo:
http://jsfiddle.net/5832R/2/
Issues:
I don't know if it works on Firefox, because the animation doesn't seem to work there...
Clone works pretty good on paused Karaoke:
On IE11 had to force a reflow (R. Krupiński's shorter version).
$('#lyrics').text("Why does it hurt when I pee?");
changeLyrics('3s');
function changeLyrics(sec) {
str = 'lyrics '+ sec + ' linear 1';
$('#lyrics').css( 'animation', str);
$('#lyrics').css( 'animation-play-state', 'running' );
$('#lyrics').replaceWith($('#lyrics').clone(true));
}
or you can use the following:
function resetAnimation(elm) {
$('#'+elm).replaceWith($('#'+elm).clone(true));
}
Reset the value first. Use reflow to apply the change without using timeout:
function shake() {
var box = document.getElementById("box");
box.style.animationName = null;
box.offsetHeight; /* trigger reflow */
box.style.animationName = "shake";
}
#keyframes shake {
0% { left: 0; }
25% { left: 12px; }
50% { left: 0; }
75% { left: -12px; }
100% { left: 0; }
}
#box {
position: absolute;
width: 75px; height: 75px;
background-color: black;
animation-duration: .02s;
animation-iteration-count: 10;
animation-timing-function: linear;
}
button {
position: absolute;
top: 100px;
}
<div id="box"></div>
<button onclick="shake()">Shake</button>
In contrast to the accepted answer that recommends animationEnd, this method resets the animation even when it's still in progress. This might be or might be not what you want.
An alternative would be to create a duplicate #keyframes animation and switch between the two:
function shake() {
var box = document.getElementById("box");
if (box.style.animationName === "shake")
box.style.animationName = "shake2";
else
box.style.animationName = "shake";
}
#keyframes shake {
0% { left: 0; }
25% { left: 12px; }
50% { left: 0; }
75% { left: -12px; }
100% { left: 0; }
}
#keyframes shake2 {
0% { left: 0; }
25% { left: 12px; }
50% { left: 0; }
75% { left: -12px; }
100% { left: 0; }
}
#box {
position: absolute;
width: 75px; height: 75px;
background-color: black;
animation-duration: .02s;
animation-iteration-count: 10;
animation-timing-function: linear;
}
button {
position: absolute;
top: 100px;
}
<div id="box"></div>
<button onclick="shake()">Shake</button>
Is there an issue with using setTimeout() to remove the class and then read it 5ms later?
svg.classList.remove('animate');
setTimeout(function() {
svg.classList.add('animate');
}, 10);
With your javascript, you could also add (and then remove) a CSS class in which the animation is declared. See what I mean ?
#cart p.anim {
animation: demo 1s 1; // Fire once the "demo" animation which last 1s
}
1) Add animation name to the #box.trigger in css
#box.trigger{
display:table;
animation:shake .2s 0 linear 1;
-moz-animation:shake .2s 0 linear 1;
-webkit-animation:shake .2s 0 linear 1;
}
2) In java-script you cannot remove the class trigger.
3) Remove the the class name by using setTimeOut method.
$(document).ready(function(){
$('#shake-the-box').click(function(){
$('#box').addClass('trigger');
setTimeout(function(){
$("#box").removeClass("trigger")},500)
});
});
4) Here is the DEMO.