I have an element which is invisible at first (opacity: 0).
When an animation is triggered, it fades in, but since the value of opacity seems to get reset, it vanishes again after completion.
How do I prevent a reset of the animated properties?
Example context:
HTML:
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" />
<div >
<div id="test1"></div>
</div>
CSS:
#test1 {
position: absolute;
margin: 10%;
width: 25%;
height: 25%;
opacity: 0;
background: blue;
}
The code below uses this JS function to add animation classes (found on the animate.css website):
const animateCSS = (element, animation, prefix = 'animate__') =>
// We create a Promise and return it
new Promise((resolve, reject) => {
const animationName = `${prefix}${animation}`;
const node = document.querySelector(element);
node.classList.add(`${prefix}animated`, animationName);
// When the animation ends, we clean the classes and resolve the Promise
function handleAnimationEnd(event) {
event.stopPropagation();
node.classList.remove(`${prefix}animated`, animationName);
resolve('Animation ended');
}
node.addEventListener('animationend', handleAnimationEnd, {once: true});
});
Here I try to trigger an in animation, wait for a moment and then have an out animation.
The described problem manifests as a flickering (can be seen in this jsfiddle.)
First I thought that the solution should be as easy as changing the property.
after completion:
let test1 = document.getElementById("test1"); animateCSS("#test1", "flipInX") // flickers .then(()=>{ test1.style.opacity = 1; }); ... animateCSS("#test1", "flipOutX") .then(()=>{ test1.style.opacity = 0; });immediately:
let test1 = document.getElementById("test1"); animateCSS("#test1", "flipInX") test1.style.opacity = 1; ... animateCSS("#test1", "flipOutX") // flickers test1.style.opacity = 0;
Then I thought that the flickering is caused by any animation delay.
So I disabled that:test1.style.setProperty('--animate-delay', '0s');` document.documentElement.style.setProperty('--animate-delay', '0s');Without any effect.
What am I doing wrong?
I use animate.css 4.1.1 with Google Chrome.
CodePudding user response:
I'd suggest you replacing opacity with transform in a separate class, and toggle that class depending on animation type ("in" or "out") when animationend fires.
Also it's better to set event handler before starting the animation.
const animateCSS = (element, animation, prefix = 'animate__') =>
new Promise((resolve, reject) => {
const animationName = `${prefix}${animation}`;
const node = document.querySelector(element);
const handleAnimationEnd = event => {
event.stopPropagation();
node.classList.remove(`${prefix}animated`, animationName);
node.classList.toggle('out', /out/i.test(animation));
}
node.addEventListener('animationend', handleAnimationEnd, {once: true});
node.classList.add(`${prefix}animated`, animationName);
});
// Test ------------------------------------------------------------
setTimeout(() => animateCSS("#test1", "flipInX"), 1000);
setTimeout(() => animateCSS("#test1", "flipOutX"), 3000);
setTimeout(() => animateCSS("#test1", "flipInX"), 6000);
setTimeout(() => animateCSS("#test1", "flipOutX"), 9000);
#test1 {
position: absolute;
width: 75%;
height: 75%;
background: blue;
}
.out {
transform:translateX(-9999vw)
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" />
<div id="test1" ></div>
CodePudding user response:
Couple of issues here:
- Animations
flipInX, andflipOutXalready controls opacity. You don't have to manage it yourself. - As soon as you remove the animation class from an element, animation effect are undone and its state resets. So removing animation classes immediately after animation end doesn't preserve the end state. We need to remove the old animation classes before next animation starts.
- The element animates from horizontal to vertical. So we need to set initial position of the element in the CSS as horizontal.
const animateCSS = (element, animation, lastAnim, prefix = 'animate__') => {
const animationName = `${prefix}${animation}`;
const node = document.querySelector(element);
// remove the last animation
node.classList.remove(`${prefix}animated`, `${prefix}${lastAnim}`);
// We create a Promise and return it
return new Promise((resolve, reject) => {
node.classList.add(`${prefix}animated`, animationName);
function handleAnimationEnd(event) {
event.stopPropagation();
//do not remove the class here
//node.classList.remove(`${prefix}animated`, animationName);
resolve('Animation ended');
}
node.addEventListener('animationend', handleAnimationEnd, { once: true});
});
}
// Test ------------------------------------------------------------
let test1 = document.getElementById("test1");
test1.style.setProperty('--animate-duration', '2s');
setTimeout(() => {
document.body.appendChild(document.createTextNode('1'));
animateCSS("#test1", "flipInX");
}, 1000);
setTimeout(() => {
document.body.appendChild(document.createTextNode('2'));
animateCSS("#test1", "flipOutX", "flipInX")
}, 3000);
setTimeout(() => {
document.body.appendChild(document.createTextNode('3'));
animateCSS("#test1", "flipInX", "flipOutX")
}, 6000);
setTimeout(() => {
document.body.appendChild(document.createTextNode('4'));
animateCSS("#test1", "flipOutX", "flipInX");
}, 9000);
#test1 {
position: absolute;
width: 25vw;
height: 25vw;
top:3rem;
left: 6rem;
background: blue;
/* starting state */
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" />
<div >
<div id="test1"></div>
</div>
