animationend event not firing - javascript

I am trying to add an animationend event to an element, but the event doesn't get fired. What am I doing wrong, and how can I fix it?
JSFiddle
var btn = document.getElementById('btn');
var elem = document.getElementById('elem');
var timeOutFunc;
btn.addEventListener('click', function() {
elem.classList.add('show');
clearTimeout(timeOutFunc);
timeOutFunc = setTimeout(function() {
elem.classList.remove('show')
}, 1000);
});
elem.addEventListener('animationend', function(e) {
console.log('animation ended');
});
#elem {
background-color: orange;
width: 100px;
height: 100px;
opacity: 0;
transition: opacity 500ms ease;
}
#elem.show {
opacity: 1;
transition: none;
}
<button id="btn">Press Me</button>
<div id="elem"></div>

There are two separate animating events.
animationend
transitionend
When using the css transition use transitionend, and when using #keyframes/animation, use animationend.

You need to modify the animation style property of the element this is your updated example at Jsfiddle
#elem {
background-color: orange;
width: 100px;
height: 100px;
opacity: 0;
transition: opacity 500ms ease;
}
/* Chrome, Safari, Opera */
#-webkit-keyframes myopacity {
0% { opacity: 0; }
100% { opacity: 1; }
}
#keyframes myopacity {
0% { opacity: 0; }
100% { opacity: 1; }
}
#elem.show {
WebkitAnimation : myopacity 1s 1;
animation : myopacity 1s 1;
}
var btn = document.getElementById('btn');
var elem = document.getElementById('elem');
var timeOutFunc;
btn.addEventListener('click', function() {
elem.classList.add('show');
/* clearTimeout(timeOutFunc);
timeOutFunc = setTimeout(function() {
elem.classList.remove('show')
}, 1000);*/
});
elem.addEventListener('animationend', function(e) {
console.log('');
alert('animation ended');
elem.classList.remove('show')
});
<button id="btn">Press Me</button>
<div id="elem"></div>

Related

CSS Animation Won't Play Per Click

I built a carousel for some images. I need my 'next' and 'previous' buttons to use the CSS animation that I assigned them in my javascript function for their event listeners.The animation will only play for one click, and when the buttons are clicked again to navigate the carousel the animation doesn't play. I need the buttons to grow and shrink for every click.
Here's the CSS:
.carousel-actions {
position: absolute;
display: flex;
justify-content: space-between;
width: 105%;
top: 30%;
}
.carousel-actions button {
padding: 30px 50px;
background-color: rgba(255, 255, 255, 0.329);
font-weight: 900;
cursor: pointer;
border-radius: 100px;
border: 0;
font-size: 60px;
color: black;
outline: none;
}
#keyframes grow {
0% {
transform: scale(1);
}
50% {
transform: scale(1.3);
}
100% {
transform: scale(1);
}
}
Here's the HTML:
<div class="carousel-actions">
<button id="prev" aria-label="Previous Slide"><</button>
<button id="next" aria-label="Next Slide">></button>
</div>
Here's the JS:
const slides = document.querySelectorAll(".carousel-item");
const totalSlides = slides.length;
let slidePosition = 0;
console.log(totalSlides);
const next = document.getElementById("next");
const prev = document.getElementById("prev");
function hideAllSlides() {
for (const slide of slides) {
slide.classList.remove("carousel-item-visible") &&
slide.classList.add("carousel-item-hidden");
}
}
function nextSlide() {
hideAllSlides();
if (slidePosition === totalSlides - 1) {
slidePosition = 0;
} else {
slidePosition++;
}
slides[slidePosition].classList.add("carousel-item-visible");
next.style.animation = "grow 1s";
}
function prevSlide() {
hideAllSlides();
if (slidePosition === 0) {
slidePosition = totalSlides - 1;
} else {
slidePosition--;
}
slides[slidePosition].classList.add("carousel-item-visible");
prev.style.animation = "grow 1s";
}
next.addEventListener("click", nextSlide);
prev.addEventListener("click", prevSlide);
The problem is seen because once the system has played the animation it thinks 'well, I've played it'. Setting it to the same again does not make it play again.
To get round this you can unset the animation when it has finished.
In your code add an event listener for the animationend event.
Here's a simplified example:
const div = document.querySelector('div');
div.addEventListener('click', function() { div.style.animationName='grow';});
div.addEventListener('animationend', function() { div.style.animationName='';});
div {
width: 100px;
height: 100px;
background-color: blue;
animation-duration: 1s;
animation-iteration-count: 1;
}
#keyframes grow {
0% {
transform: scale(1);
}
50% {
transform: scale(1.3);
}
100% {
transform: scale(1);
}
<div></div>

Behavior of the body after the animation end on the body

I have a problem. I made a CSS animation on the body, going from one color to the other for like 10 seconds, only showing one image and one paragraph, and ignoring the rest of the paragraphs and other stuff written in my HTML code.
When the animation is finished, I would like that the body displays the actual HTML content (other paragraphs and DIV's, etc.). Now that is the problem, I tried with opacity and setting it to 0 during the animation and then resetting it to 1 after the animation ends but I could not do it? Could you help me? I created the animations in JS with event listeners and keyframes in CSS.
let backColor = document.querySelector('body');
let banner = document.querySelector('#banner p');
let img = document.querySelector('#banner img');
function myMove() {
backColor.style.WebkitAnimation = 'mymove 7s 1s 1 forwards';
backColor.style.animation = 'mymove 7s 1s 1 forwards';
}
backColor.addEventListener('animationstart', () => {
this.style.backgroundColor = 'white';
});
backColor.addEventListener('animationend', () => {
this.style.backgroundColor = 'black';
});
myMove();
function yourMove() {
banner.style.WebkitAnimation = 'yourmove 6s 4s 1';
banner.style.animation = 'yourmove 6s 4s 1';
}
banner.addEventListener('animationstart', () => {
this.style.opacity = 0;
});
banner.addEventListener('animationend', () => {
this.style.opacity = 1;
});
yourMove();
function hisMove() {
img.style.WebkitAnimation = 'hismove 3s 6s 1';
img.style.animation = 'hismove 3s 6s 1';
}
img.addEventListener('animationstart', () => {
this.style.opacity = 0;
});
img.addEventListener('animationend', () => {
this.style.opacity = 1;
});
hisMove();
body {
margin: 0;
padding: 0;
}
#keyframes mymove {
from {
background-color: white;
}
to {
background-color: black;
}
}
#banner p {
color: white;
font-size: 25px;
font-family: Georgia;
opacity: 0;
text-align: center;
}
img {
position: relative;
left: 35%;
opacity: 0;
}
#keyframes yourmove {
0% {
opacity: 0;
}
50% {
opacity: 1;
}
100% {
opacity: 0;
}
}
#keyframes hismove {
0% {
opacity: 0;
}
50% {
opacity: 1;
}
100% {
opacity: 0;
}
}
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div id="banner">
<p>In the loving memory of <br />Kobe Bryant (1978 - 2020)</p>
<img src="https://i.ytimg.com/vi/tiE7aa9HTec/maxresdefault.jpg" width="450" height="300">
</div>
<div id="container">
<!-- rest of the html content -->
</div>
<script type="text/javascript" src="kobe.js"></script>
</body>
</html>
Wouldn't had make it this way,but it's fixed:
let backColor = document.querySelector('body');
let banner = document.querySelector('#banner p');
let img = document.querySelector('#banner img');
function myMove() {
backColor.style.WebkitAnimation = 'mymove 7s 1s 1 forwards';
backColor.style.animation = 'mymove 7s 1s 1 forwards';
}
backColor.addEventListener('animationstart', () => {
backColor.style.backgroundColor = 'white';
});
backColor.addEventListener('animationend', () => {
backColor.style.backgroundColor = 'black';
});
myMove();
function yourMove() {
banner.style.WebkitAnimation = 'yourmove 6s 4s 1';
banner.style.animation = 'yourmove 6s 4s 1';
}
banner.addEventListener('animationstart', () => {
banner.style.opacity = 0;
});
banner.addEventListener('animationend', () => {
banner.style.opacity = 1;
});
yourMove();
function hisMove() {
img.style.WebkitAnimation = 'hismove 3s 6s 1';
img.style.animation = 'hismove 3s 6s 1';
}
img.addEventListener('animationstart', () => {
img.style.opacity = 0;
});
img.addEventListener('animationend', () => {
img.style.opacity = 1;
});
hisMove();
body {
margin: 0;
padding: 0;
color: white;
}
#keyframes mymove {
from {
background-color: white;
}
to {
background-color: black;
}
}
#banner p {
color: white;
font-size: 25px;
font-family: Georgia;
opacity: 0;
text-align: center;
}
img {
position: relative;
left: 35%;
opacity: 0;
}
#keyframes yourmove {
0% {
opacity: 0;
}
50% {
opacity: 1;
}
100% {
opacity: 0;
}
}
#keyframes hismove {
0% {
opacity: 0;
}
50% {
opacity: 1;
}
100% {
opacity: 0;
}
}
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div id="banner">
<p>In the loving memory of <br />Kobe Bryant (1978 - 2020)</p>
<img src="https://i.ytimg.com/vi/tiE7aa9HTec/maxresdefault.jpg" width="450" height="300">
</div>
<div id="container">
<!-- rest of the html content -->
RIP RIP RIP RIP RIP RIP
</div>
<script type="text/javascript" src="kobe.js"></script>
</body>
</html>

How to add CSS transition on closing event of a details tag?

After reading those two questions:
How To Add CSS3 Transition With HTML5 details/summary tag reveal?
How to make <'details'> drop down on mouse hover
I have a new one for you!
Problem
I want an animation on closing event of the <details> tag. I thought that just revert the animation of opening would do the job, but unfortunately, no.
$(function() {
$('details').on('mouseover', function() {
$(this).attr('open', true);
}).on('mouseout', function() {
$(this).attr('open', false);
}).on('click', function(e) {
e.preventDefault();
})
});
details[open] SUMMARY~* {
animation: sweepin .5s ease-in-out;
}
details[close] SUMMARY~* {
animation: sweepout .5s ease-in-out;
}
#keyframes sweepin {
0% {
opacity: 0;
margin-left: -10px
}
100% {
opacity: 1;
margin-left: 0px
}
}
#keyframes sweepout {
0% {
opacity: 1;
margin-left: 0px
}
100% {
opacity: 0;
margin-left: -10px
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<details>
<summary>Here my little summary</summary>
<p>... Do you want more details?</p>
<p>Here have some details!</p>
</details>
Question
Do you think this is possible?
You can substitute toggling .className for details[close] selector; at mouseover event check if element is not .open, if true, set property to .open = true at mouseout event add .className, use .one() animationend event to remove .className and set .open to false at event handler.
$(function() {
$("details").on({
mouseover: function() {
if (!this.open && !$(this).is(".close"))
$(this).prop("open", true)
.one("animationend", function() {
$(this).addClass("animationDone")
})
},
mouseout: function _close() {
if (!$(this).is(".close") && $(this).is(".animationDone"))
$(this).addClass("close")
.one("animationend", function() {
$(this).prop("open", false)
.removeClass("close animationDone")
})
},
click: function(e) {
e.preventDefault();
}
})
});
details[open] SUMMARY~* {
animation: sweepin .5s ease-in-out;
}
details.close SUMMARY~* {
animation: sweepout .5s ease-in-out;
}
#keyframes sweepin {
0% {
opacity: 0;
margin-left: -10px
}
100% {
opacity: 1;
margin-left: 0px
}
}
#keyframes sweepout {
0% {
opacity: 1;
margin-left: 0px
}
100% {
opacity: 0;
margin-left: -10px
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<details>
<summary>Here my little summary</summary>
<p>... Do you want more details?</p>
<p>Here have some details!</p>
</details>
Sorry for change the logic, but I've found this faster and fluid.
$(function() {
$('#summary').on('mouseover', function() {
$('#triangleDown').fadeIn(0);
$('#triangle').fadeOut(0);
$('#content').addClass("open");
}).on('mouseout', function() {
$('#triangleDown').fadeOut(0);
$('#triangle').fadeIn(0);
$('#content').removeClass("open");
})
});
#triangleDown{
display:none;
}
span{
font-size: 12px;
}
#content{
opacity:0;
margin-left: 0px;
-webkit-transition:all 1s;
transition:all 1s;
}
#content.open{
opacity: 1;
margin-left: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<p id="summary"><span id="triangle">► </span><span id="triangleDown">▼ </span>Here my little summary</p>
<div id="content">
<p>... Do you want more details?</p>
<p>Here have some details!</p>
</div>
</div>
You can use an animation-fill-mode property to keep the original position of the div after animation is completed. On mouseover and mouse out event, you can add and remove the open and close attribute.
See snippet below
$(function() {
$('details').on('mouseover', function() {
$(this).attr('open', true);
$(this).removeAttr('close', false);
}).on('mouseout', function() {
$(this).attr('open', false);
$(this).removeAttr('open', false);
$(this).attr('close', true);
}).on('click', function(e) {
e.preventDefault();
})
});
details[open] SUMMARY~* {
animation: sweepin .5s ease-in-out;
animation-fill-mode:forwards;
}
details[close] SUMMARY~* {
animation: sweepout .5s ease-in-out;
animation-fill-mode:forwards;
}
#keyframes sweepin {
0% {
opacity: 0;
margin-left: -10px
}
100% {
opacity: 1;
margin-left: 0px
}
}
#keyframes sweepout {
0% {
opacity: 1;
margin-left: 0px;
}
100% {
opacity: 0;
margin-left: -10px
}
}
details{
border:solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<br><br><br><br>
<details>
<summary>Here my little summary</summary>
<p>... Do you want more details?</p>
<p>Here have some details!</p>
</details>

CSS slide in from left animation

I'm working on a slideshow and it works, except for the animations. The animation for sliding out works fine but the animation for sliding in from the left does not. The left margin gets set to 0% but there is no animation, even though it is set to -100% at first.
Javascript:
var images = [
'http://i.imgur.com/ByyUANz.png',
'http://i.imgur.com/S5FfOOB.png',
'http://i.imgur.com/EuefPdv.png',
'http://i.imgur.com/Ucvm4pJ.png',
'http://i.imgur.com/pK5WBHN.png',
'http://i.imgur.com/nuOLVpy.png'
]
function slideShow(startAt){
var holder = document.getElementById("currentImage");
var img = document.createElement("img");
img.src = images[startAt];
holder.appendChild(img);
nextPicture(startAt, img);
}
function nextPicture(current, currentElement){
var holder = document.getElementById("currentImage");
setTimeout(function(){
currentElement.className = "translateLeft";
current += 1;
var img = document.createElement("img");
img.src = images[current];
img.style.marginLeft = "-100%";
holder.appendChild(img);
img.className = "translateIn";
if (current == 5){
current = -1;
nextPicture(current, img);
} else {
nextPicture(current, img);
}
}, 5000)
}
slideShow(0);
CSS:
.translateLeft {
transition: 3s;
margin-left: 100% !important;
}
.translateIn {
transition: 3s;
margin-left: 0% !important;
}
Here is a solution for you.
https://jsfiddle.net/smaefwrp/2/
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
html,
body,
img {
position: absolute;
top:0;
left: 0;
margin: 0;
padding: 0;
height: 100%;
overflow-x: hidden;
}
#currentImage {
height: 100%;
width: 1920px;
}
.translateOrigin {
transition: none;
transform: translate3d(-100%, 0, 0) !important;
}
.translateLeft {
transition: transform 3s;
transform: translate3d(100%, 0, 0) !important;
}
.translateIn {
transition: transform 3s;
transform: translate3d(0, 0, 0) !important;
}
</style>
</head>
<body>
<div id="currentImage">
</div>
<div id="buttons">
</div>
<script type="text/javascript">
var images = [
'http://i.imgur.com/ByyUANz.png',
'http://i.imgur.com/S5FfOOB.png',
'http://i.imgur.com/EuefPdv.png',
'http://i.imgur.com/Ucvm4pJ.png',
'http://i.imgur.com/pK5WBHN.png',
'http://i.imgur.com/nuOLVpy.png'
];
var imageEle = [];
var currImage = 0;
var holder = document.getElementById("currentImage");
function imagesPreload() {
for (var i = 0; i < images.length; i++) {
var img = new Image();
img.src = images[i];
img.className = "translateOrigin";
holder.appendChild(img);
imageEle.push(img);
}
}
imagesPreload();
document.onkeydown = function(event){
if(event.keyCode === 13) {
nextPicture();
}
};
function slideShow(startAt) {
var holder = document.getElementById("currentImage");
imageEle[currImage].className = "translateIn";
nextPicture();
}
function nextPicture() {
setTimeout(function () {
var img = imageEle[currImage];
img.addEventListener("transitionend", transitionEnd, false);
img.className = "translateLeft";
if (currImage == 5) {
currImage = 0;
} else {
currImage++;
}
imageEle[currImage].className = "translateIn";
/* Reset the image to original position */
function transitionEnd() {
img.className = "translateOrigin";
img.removeEventListener("transitionend", transitionEnd, false);
nextPicture();
}
}, 5000)
}
slideShow(currImage);
</script>
</body>
</html>
To create a nice slideshow I suggest to use css transform property rather than the margin. The idea is to create the placeholder element currentImage with relative position, and then create all images inside it with position set to absolute. Then by default all images are translated out of the placeholder element, and adding/removing classes show and hide you can place them inside the view and then outside of it, like this:
var images = [
'http://i.imgur.com/ByyUANz.png',
'http://i.imgur.com/S5FfOOB.png',
'http://i.imgur.com/EuefPdv.png',
'http://i.imgur.com/Ucvm4pJ.png',
'http://i.imgur.com/pK5WBHN.png',
'http://i.imgur.com/nuOLVpy.png'
];
// Get the holder
var holder = document.getElementById("currentImage");
// Create the images
images.forEach(function(url) {
var img = document.createElement("img");
img.src = url;
holder.appendChild(img);
});
// Image counter
var counter = 0;
// Slide show interval
var slideshow = setInterval(function() {
// When we reach the end of images we shut down the slide show
// or you can reset the counter to start over
if(counter === images.length) {
clearInterval(slideshow);
return;
}
// Get all images
var nodes = holder.getElementsByTagName("img");
// Hide previous image
if(nodes[counter - 1]) {
nodes[counter - 1].className = "hide";
}
// Show next image
nodes[counter].className = "show";
counter++;
}, 2500);
#currentImage {
background: gray;
width: 300px;
height: 300px;
margin: 0 auto;
position: relative;
overflow: hidden;
}
#currentImage img {
width: 100%;
position: absolute;
transform: translateX(-110%);
-webkit-transition: -webkit-transform 1.0s ease 0s;
-moz-transition: -moz-transform 1.0s ease 0s;
-o-transition: -o-transform 1.0s ease 0s;
transition: transform 1.0s ease 0s;
}
#currentImage img.show {
transform: translateX(0%);
}
#currentImage img.hide {
transform: translateX(110%);
}
<div id="currentImage">
</div>
You can try something like:
// HTML
<div id="currentImage">
<div class="window">
<div class="image-list">
<div>
<img src="http://i.imgur.com/ByyUANz.png" />
</div>
<div>
<img src="http://i.imgur.com/S5FfOOB.png" />
</div>
<div>
<img src="http://i.imgur.com/EuefPdv.png" />
</div>
<div>
<img src="http://i.imgur.com/Ucvm4pJ.png" />
</div>
<div>
<img src="http://i.imgur.com/pK5WBHN.png" />
</div>
<div>
<img src="http://i.imgur.com/nuOLVpy.png" />
</div>
</div>
</div>
</div>
And CSS
// CSS
img {
height: 50px;
width: 50px
}
.window {
position: absolute;
height: 50px;
width: 50px;
border: 2px solid red;
overflow: hidden
}
div {
display: inline-block
}
.image-list {
list-style-type: none;
display: inline-block;
padding-left: 0px;
margin: 0px;
width: 350px;
animation: slidingli 30s ;
}
#keyframes slidingli {
0% {
transform: translateX(0px)
}
16% {
transform: translateX(-50px)
}
32% {
transform: translateX(-100px)
}
48% {
transform: translateX(-150px)
}
64% {
transform: translateX(-200px)
}
80% {
transform: translateX(-250px)
}
100% {
transform: translateX(-300px)
}
}
Checkout this fiddle. Also there are many libraries out there which provide what need For example: http://fotorama.io/customize/autoplay/

pull variable from css with js

I'm trying to get an action to occur when one clicks on an image, however only when the image is at full opacity
function func() {
if ($('.Absolute-Center').css('opacity') == 1) {
alert("it works");
}
}
.Absolute-Center {
margin: auto;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
img.Absolute-Center {
opacity: 0.05;
filter: alpha(opacity=5);
-webkit-transition: opacity 20s linear;
}
img.Absolute-Center:hover {
opacity: 1;
filter: alpha(opacity=100);
-webkit-transition: opacity 20s linear;
}
<img src="picture.png" class="Absolute-Center" onclick="func()" />
Try using transitionend event , .addClass() , .removeClass() ; removing :hover from css
function func(e) {
if ($(this).css("opacity") == 1) {
alert("it works");
$(this).removeClass("clicked")
}
};
$(".Absolute-Center").on({
"click": function() {
$(this).addClass("clicked")
},
"transitionend": func
})
.Absolute-Center {
margin: auto;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
img.Absolute-Center {
opacity: 0.05;
filter: alpha(opacity=5);
transition: opacity 20s linear;
}
img.Absolute-Center.clicked {
opacity: 1;
filter: alpha(opacity=100);
transition: opacity 20s linear;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<img src="http://lorempixel.com/50/50" class="Absolute-Center" />
This should help improve understanding and should be easily adaptable to do exactly what you want.
$(function() {
$('img').on('click', function() {
var alpha = $(this).css('opacity');
$("#msg").text((alpha == 1) ? "full" : alpha);
}).on('transitionend', function() {
var alpha = $(this).css('opacity');
if (alpha == 1) {
$("#msg2").fadeIn().delay(700).fadeOut();
} else {
$("#msg3").fadeIn().delay(700).fadeOut();
}
});
});
img {
border: 1px solid #000;
}
img {
opacity: 0.05;
filter: alpha(opacity=5);
-webkit-transition: opacity 5s linear;
}
img:hover {
opacity: 1;
filter: alpha(opacity=100);
-webkit-transition: opacity 5s linear;
}
#msg2, #msg3 {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<img src="picture.png" />
<div>Last clicked at opacity: <span id="msg"></span>
</div>
<div id="msg2">End of fade-IN transition</div>
<div id="msg3">End of fade-OUT transition</div>

Categories

Resources