My animation function only runs once. I've tried removing and adding classes, as well as running a animationend function to create a retrigger. But still no luck. Any vanilla JS ideas?
CSS:
#element {
width: 10px;
height: 10px;
animation: "";
#keyframes movedown {
100% {
transform: translateY(10px);
}
}
JS:
btn_button.onclick = () => {
element.style.animation = "movedown 10s";
};
HTML:
<div id="element"></div>
You can use setTimeout to set element.style.animation to "". Then, you can add animation name again upon button click.
let btn = document.querySelector("#btn");
btn.onclick = () => {
element.style.animation = "movedown 2s";
setTimeout(() => element.style.animation = "", 2000)
};
#element {
width: 10px;
height: 10px;
background-color: red;
}
#keyframes movedown {
100% {
transform: translateY(50px);
}
}
<div id="element"></div>
<button id="btn">Trigger</button>
Related
Consider such div:
<div id="someid"></div>
And it's style:
#someid {
transition: background-color 10s ease;
background-color: #FF0000;
height: 100px;
width: 100px;
}
#someid:hover {
background-color: #FFFFFF;
}
I want to have a possibility to detect state (currently animating or not) of #someid via JS and/or end animation if that's possible. I've tried a thing from this answer:
document.querySelector("#someid").style.transition = "none";
but it didn't work for currently animating element.
The point is I need to detect whether element is animating now and if so, wait for animation to end or end it immediately, otherwise do nothing
I've already found transitionend event, but using it I can't detect whether element is animating at the moment.
You can listen to transition event and remove it on demand:
const el = document.getElementById('transition');
let isAnimating = false;
el.addEventListener('transitionstart', function() {
isAnimating = true;
});
el.addEventListener('transitionend', () => {
isAnimating = false;
});
el.addEventListener('transitioncancel', () => {
isAnimating = false;
});
function removeTransition(checkIfRunning) {
if (checkIfRunning && !isAnimating) {
return;
}
el.style.transition = "none";
}
#transition {
width: 100px;
height: 100px;
background: rgba(255, 0, 0, 1);
transition-property: transform background;
transition-duration: 2s;
transition-delay: 1s;
}
#transition:hover {
transform: rotate(90deg);
background: rgba(255, 0, 0, 0);
}
<div id="transition">Hello World</div>
<br />
<button onclick="removeTransition(false)">Remove Transition</button>
<br />
<br />
<button onclick="removeTransition(true)">Remove Transition on if running</button>
I have a problem where when I click an element with an 'onclick' function, it works just as normal but when I click another element with a different 'onclick' function, the first 'onclick' function will remain. Instead, I want to be able able to reverse(?) the first function so that it is no longer active.
These are h1 tags that are meant to act as nav and when I click on one of them they change their styles.
Here is my code:
function aboutActive() {
var about = document.querySelector('.about');
about.classList.toggle('about-active');
}
function contactActive() {
var contact = document.querySelector('.contact');
contact.classList.toggle('contact-active');
}
function discoverActive() {
var discover = document.querySelector('.discover');
discover.classList.toggle('discover-active');
}
function signUpActive() {
var signUp = document.querySelector('.sign-up');
signUp.classList.toggle('signUp-active');
}
.about {
position: absolute;
left: 70.8%;
top: 5%;
transition: transform 0.8s ease-in;
transition: 0.8s ease-in;
}
.contact {
position: absolute;
left: 56%;
top: 24%;
transition: transform 0.8s ease-in;
transition: 0.8s ease-in;
}
.discover {
position: absolute;
left: 52.7%;
top: 43%;
transition: transform 0.8s ease-in;
transition: 0.8s ease-in;
}
.sign-up {
width: 100%;
position: absolute;
left: 62.6%;
top: 63%;
transition: transform 0.8s ease-in;
transition: 0.8s ease-in;
}
/* New styles applied by JS */
.about-active {
transform: translateX(-30%);
color: #ffffff;
}
.contact-active {
transform: translateX(-22%);
color: #ffffff;
}
.discover-active {
transform: translateX(-24%);
color: #ffffff;
}
.signUp-active {
transform: translateX(-14.2%);
color: #ffffff;
}
<h1 class="about" onmouseover=cursorEnlargeLarge() onmouseout=cursorNormal() onclick="aboutActive()">ABOUT</h1>
<h1 class="contact" onmouseover=cursorEnlargeLarge() onmouseout=cursorNormal() onclick="contactActive()">CONTACT</h1>
<h1 class="discover" onmouseover=cursorEnlargeLarge() onmouseout=cursorNormal() onclick="discoverActive()">DISCOVER</h1>
<h1 class="sign-up" onmouseover=cursorEnlargeLarge() onmouseout=cursorNormal() onclick="signUpActive()">SIGN UP</h1>
These are the functions that toggle through the styles when clicked on.
To reiterate, when I click on one of the h1 element, it does its 'onclick' function normally but if I want to click on a second h1 element, the second element's function will activate but the first will stay. How would I change it so that any previous functions will be reversed/uncalled?
function undo(ele){
let cl = ele.classList;
ele.classList.remove(cl[cl.length - 1], cl[cl.length - 2]);
}
function aboutActive() {
let about = document.querySelector('.about');
let current = document.querySelector(".current");
if(current) undo(current);
about.classList.toggle('about-active');
about.classList.add("current");
}
function contactActive() {
let contact = document.querySelector('.contact');
let current = document.querySelector(".current");
if(current) undo(current);
contact.classList.toggle('contact-active');
contact.classList.add("current");
}
I'm just adding 'current' class to active element.
If 'current' already exists then remove last 2 classes of the 'current' element.
It's not the best one but it works.
(well it's my first answer on stackoverflow so don't hate on me please)
From what I understand, you want when you click on other function uncall function you clicked before
var about = document.querySelector('.about');
var contact = document.querySelector('.contact');
function aboutActive() {
about.classList.toggle('about-active', true);
}
function contactActive() {
about.classList.toggle('about-active', false);
contact.classList.toggle('contact-active');
}
Add a Reset function before click of any H1 which will reset all the h1 tag click
function aboutActive() {
resetAll();
var about = document.querySelector('.about');
about.classList.toggle('about-active');
}
function contactActive() {
resetAll();
var contact = document.querySelector('.contact');
contact.classList.toggle('contact-active');
}
function discoverActive() {
resetAll();
var discover = document.querySelector('.discover');
discover.classList.toggle('discover-active');
}
function signUpActive() {
resetAll();
var signUp = document.querySelector('.sign-up');
signUp.classList.toggle('signUp-active');
}
function resetAll() {
var getheading = document.getElementsByTagName("H1");
[].forEach.call(getheading, function(el) {
var classes = el.className.split(" ").filter(c => !c.endsWith("-active"));
el.className = classes.join(" ").trim();
})
}
.about-active {
transform: translateX(-30%);
color: #ffffff;
}
.contact-active {
transform: translateX(-22%);
color: #ffffff;
}
.discover-active {
transform: translateX(-24%);
color: #ffffff;
}
.signUp-active {
transform: translateX(-14.2%);
color: #ffffff;
}
<h1 class="about" onclick="aboutActive()">ABOUT</h1>
<h1 class="contact" onclick="contactActive()">CONTACT</h1>
<h1 class="discover" onclick="discoverActive()">DISCOVER</h1>
<h1 class="sign-up" onclick="signUpActive()">SIGN UP</h1>
So what I ended up doing is just removing the active class when I call the function:
function aboutActive() {
var about = document.querySelector('.about');
var contact = document.querySelector('.contact');
var discover = document.querySelector('.discover');
var signUp = document.querySelector('.sign-up');
about.classList.toggle('about-active');
contact.classList.remove('contact-active');
discover.classList.remove('discover-active');
signUp.classList.remove('signUp-active');
}
I have to this for every h1 element so it isn't the best way but it works.
I implemented a infinite loop animation using setInterval. I now like to change the implementation to requestAnimationFrame() so that I will have performance which I am after. For some reasons, requestAnimationFrame() does not call the function supplied to it.
My code looks like this;
var index = 0;
var $btn = $('.btn');
function btnBlinkRun() {
if (index < 2) {
index = index + 1;
} else {
index = 0;
}
$('#ani--scaleinout').removeAttr('id');
$($btn[index]).attr('id', 'ani--scaleinout');
window.requestAnimationFrame(btnBlinkRun);
}
btnBlinkRun();
.btn{
width: 30px;
height: 30px;
background: blue;
border-radius: 100%;
margin-bottom: 10px;
}
#ani--scaleinout {
animation: zoominout 1s ease-in;
}
#keyframes zoominout {
50% {
transform: scale(1.4);
}
100% {
transform: scale(1);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<div class="btn" id="ani--scaleinout"></div>
<div class="btn"></div>
<div class="btn"></div>
</div>
It looks like what's going on is you are firing requestAnimationFrame multiple times per second. Your css animation has a duration of 1s. But you are removing the attribute every x ms.
It is triggering, it's just happening so fast you can't see it. To demonstrate change your call to window.requestAnimationFrame to use a setTimeout and you'll notice the animation:
setTimeout(function() {
window.requestAnimationFrame(btnBlinkRun);
}, 1000);
Not saying this is a preferred solution, but explaining why this is happening.
It executes alright. But it does not do what you want it to, i presume.
Animation frame fires on every single rending frame (e.g. 60fps) and not on CSS animation keyframes.
The animationend event is your friend here.
var index = 0;
var buttons = document.querySelectorAll('.btn');
function btnBlinkRun() {
if (index < 2) {
index = index + 1;
} else {
index = 0;
}
const element = document.querySelector('#ani--scaleinout');
element.id = null;
buttons[index].id = 'ani--scaleinout';
buttons[index].addEventListener("animationend", btnBlinkRun, { once: true });
}
btnBlinkRun();
.btn{
width: 30px;
height: 30px;
background: blue;
border-radius: 100%;
margin-bottom: 10px;
}
#ani--scaleinout {
animation: zoominout 1s ease-in;
}
#keyframes zoominout {
50% {
transform: scale(1.4);
}
100% {
transform: scale(1);
}
}
<div>
<div class="btn" id="ani--scaleinout"></div>
<div class="btn"></div>
<div class="btn"></div>
</div>
I am trying animating an element which has display property set to null. Objective is to recreate something that bootstrap does in modal.
Further Explanation:
An element which is set to display none on page load but when a user clicks a certain button it shows up with animation (fade in for example). Then when user click on close button or that button again it fades out and its display property is set to none again.
Problem:
When box display property is set to none. And i click on the button. It's display is set to block and adding class "Show" both occur simultaneously and instantaneously so element just shows rather than animating
Here is my Code:
HTML:
<button id="btn">Show / Hide</button>
<div id="box" class="show">
</div>
CSS:
#box {
background-color: aquamarine;
height: 100px;
width: 100px;
opacity: 0;
transition: ease all 0.3s;
}
#box.show {
transition: ease all 0.3s;
opacity: 1;
}
Javascript:
var box = document.querySelector("#box");
var btn = document.querySelector("#btn");
box.style.display = "none"
btn.addEventListener("click", function () {
if(box.style.display == "none") {
return new Promise(function(resolve, reject) {
box.style.display = "block";
resolve();
}).then(function() {
box.classList.add('show');
});
} else if(box.style.display == "block") {
return new Promise(function(resolve, reject) {
box.addEventListener('transitionend', function () {
box.style.display = "none";
})
resolve();
}).then(function() {
box.classList.remove('show');
});
}
});
JSFiddle: https://jsfiddle.net/ptLggbmb/1/
Instead of using Promises you could simply use the transitionend listener and for the fadeIn animation force a layout/reflow before applying the class to the box.
var box = document.querySelector("#box");
var btn = document.querySelector("#btn");
btn.addEventListener("click", function() {
var prevDisplay = box.style.display;
var listener = function() {
box.style.display = "none";
removeListener(listener);
};
if (prevDisplay !== "none") {
addListener(listener);
box.classList.remove('show');
} else {
removeListener(listener);
box.style.display = null;
box.offsetLeft;
box.classList.add('show');
}
function addListener(fn) {
box.addEventListener('transitionend', fn);
}
function removeListener(fn) {
box.removeEventListener('transitionend', fn);
}
});
#box {
background-color: aquamarine;
height: 100px;
width: 100px;
opacity: 0;
transition: ease all 0.3s;
}
#box.show {
transition: ease all 0.3s;
opacity: 1;
}
<button id="btn">Show / Hide</button>
<div id="box" class="show">
</div>
I think you overcomplicated this to the extreme, IMHO. Try this (Pure CSS with a simple JS toggle of classes):
https://jsfiddle.net/ptLggbmb/17/
HTML:
<button id="btn">Show / Hide</button>
<div id="box" class="show">
CSS:
#box {
background-color: aquamarine;
height: 100px;
width: 100px;
opacity: 0;
display: none;
transition: ease all 1s;
}
#box.show {
display: block;
opacity: 1;
}
JS:
var box = document.querySelector("#box");
var btn = document.querySelector("#btn");
btn.addEventListener("click", function () {
box.classList.toggle('show');
});
I'm trying to show an element for a short amount of time, then hiding it with a CSS transition, on a button click.
Here's the outline of what I did.
elem has a property of opacity: 0.
Fire event when button gets selected.
The events function will add, then remove a class named show to elem.
CSS has the following property: transition: opacity 500ms ease 1000ms;.
#elem.show has a property of opacity: 1.
The problem is, nothing happens when the button gets clicked on. How can I make element get shown, without a transition effect, then, after 1s close with a transition?
JSFiddle
var btn = document.getElementById('btn');
var elem = document.getElementById('elem');
btn.addEventListener('click', function() {
elem.classList.add('show');
elem.classList.remove('show');
});
#elem {
background-color: orange;
width: 100px;
height: 100px;
opacity: 0;
transition: opacity 500ms ease 1000ms;
}
#elem.show {
opacity: 1;
transition: none;
}
<button id="btn">Press Me</button>
<div id="elem"></div>
Using setTimeout is not tidy - it is better to listen to the animation end event and remove the show class. I have also used animation to show and hide the element successively - see demo below:
var btn = document.getElementById('btn');
var elem = document.getElementById('elem');
btn.addEventListener('click', function() {
elem.classList.remove('show');
// this force-restarts the CSS animation
void elem.offsetWidth;
elem.classList.add('show');
});
elem.addEventListener("animationend", function(){
elem.classList.remove('show');
}, false);
#elem {
background-color: orange;
width: 100px;
height: 100px;
opacity: 0;
}
#elem.show {
animation: anime 1s 1;
}
#keyframes anime {
0% {
opacity: 1;
}
50% {
opacity: 1;
}
100% {
opacity: 0;
}
}
<button id="btn">Press Me</button>
<div id="elem"></div>
Update
Listening to the animation-end event do not seem necessary actually - it works properly even without it. The gist here is the use of void elem.offsetWidth to forcefully restart the animation:
var btn = document.getElementById('btn');
var elem = document.getElementById('elem');
btn.addEventListener('click', function() {
elem.classList.remove('show');
// this force-restarts the CSS animation
void elem.offsetWidth;
elem.classList.add('show');
});
#elem {
background-color: orange;
width: 100px;
height: 100px;
opacity: 0;
}
#elem.show {
animation: anime 1s 1;
}
#keyframes anime {
0% {
opacity: 1;
}
50% {
opacity: 1;
}
100% {
opacity: 0;
}
}
<button id="btn">Press Me</button>
<div id="elem"></div>
just do this :
setTimeout(function() { elem.classList.remove('show'); }, 1000);
instead of writing :
elem.classList.remove('show');
To handle repeated clicks, do this ::
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);
});
This borrows from other answers, and addresses the multiple press "issue"
var btn = document.getElementById('btn');
var elem = document.getElementById('elem');
btn.addEventListener('click', (function() {
var timer = null;
return function() {
elem.classList.add('show');
if (timer) {
clearTimeout(timer);
timer = null;
}
timer = setTimeout(e => elem.classList.remove('show'), 1000);
};
})());
#elem {
background-color: orange;
width: 100px;
height: 100px;
opacity: 0;
transition: opacity 500ms ease 500ms;
}
#elem.show {
opacity: 1;
transition: none;
}
<button id="btn">Press Me</button>
<div id="elem"></div>
Try with this...i Hope its resolved your prblm
https://jsfiddle.net/b3en368p/5/
var btn = document.getElementById('btn');
var elem = document.getElementById('elem');
btn.addEventListener('click', function() {
elem.classList.add('show');
setTimeout(function(text){
elem.classList.remove('show');
}, 1000);
});
Add css
#elem {
background-color: orange;
width: 100px;
height: 100px;
display: none;
}
#elem.show {
display: block;
}
Your listener should be like this-
btn.addEventListener('click', function() {
elem.classList.add('show');
setTimeout(function(){
elem.classList.remove('show');
}, 1000);
});