I want to make a simple JavaScript onclick animation. My problem is that when I click onto the button, the animation is executed, but when I click again onto the button, nothing happens. On the third clicks the animation plays again. I want to make that, the animation plays at the second click.
Heres my code"
var anim = document.getElementById("anim");
anim.onclick = function highA() {
var willCheck = document.getElementById("contactId");
if (!willCheck.classList.contains("highAnim")) {
willCheck.classList.add("highAnim");
} else {
willCheck.classList.remove("highAnim");
}
}
#contactId { background: red;}
.highAnim {
background-color: var(--white);
animation-name: highcheck;
animation-duration: 0.35s;
animation-timing-function: ease-in-out;
}
#keyframes highcheck {
0% {transform: rotate(0);}
25% {transform: rotate(1deg);}
50% {transform: rotate(2deg);}
75% {transform: rotate(1deg);}
100% {transform: rotate(0);}
}
<a onclick="anim()" id="anim">Click</a><br><br>
<div id="contactId">Some Text</div>
The issue is because the first click adds the class and triggers the animation, yet the second (and every even numbered click) after that removes the class so nothing happens.
To fix this you can use the animationend event to remove the class automatically after the animation has ended. That way when you next click again the class is added to the element once more and the animation plays. Try this:
var anim = document.getElementById("anim");
var willCheck = document.getElementById("contactId");
anim.addEventListener('click', () => {
willCheck.classList.add("highAnim");
});
willCheck.addEventListener('animationend', () => {
willCheck.classList.remove("highAnim");
});
#contactId { background: red; }
.highAnim {
background-color: var(--white);
animation-name: highcheck;
animation-duration: 0.35s;
animation-timing-function: ease-in-out;
}
#keyframes highcheck {
0% { transform: rotate(0); }
50% { transform: rotate(2deg); }
100% { transform: rotate(0); }
}
<a id="anim">Click</a><br><br>
<div id="contactId">Some Text</div>
Note that I removed the 25% and 75% items in the animation as it's a linear motion from 0% to 50% and back again, so they are not needed. This also helps to make the animation smoother.
Another idea using animationiteration
var anim = document.getElementById("anim");
var willCheck = document.getElementById("contactId");
anim.addEventListener('click', () => {
willCheck.style.animationPlayState="running";
});
willCheck.addEventListener('animationiteration', () => {
willCheck.style.animationPlayState="paused";
});
#contactId {
background: red;
animation: highcheck 0.35s ease-in-out infinite paused;
}
#keyframes highcheck {
50% {
transform: rotate(2deg);
}
}
<a id="anim">Click</a><br><br>
<div id="contactId">Some Text</div>
Related
I am relatively new to CSS/JS and I have a problem when triggering a new CSS animation.
I have a <div> that infinitely moves through to some specific points of the screen using a CSS keyframe animation.
I have an image that, when clicked, it triggers a js. function that toggles a new CSS class / animation. My problem is that I want to start this new animation in the position that the current(or last animation) was before toggling the new class.
I don't know how to store the current position from the keyframe and make a new animation starting from it.
To simplify, I have something like this in CSS:
.block {
width: 100px;
height: 100px;
background-color: black;
position: relative;
animation: animate 10s infinite ease-in-out;
animation-play-state: running;
}
#keyframes animate {
0% {
transform: translate(-300px, 20px) rotateY(180deg) scale(1)
}
50% {
transform: translate(1200px, 200px) rotateY(180deg) scale(1.2)
}
100% {
transform: translate(200px, 100px) scale(1.2)
}
}
CSS of the new animation triggered:
.block.new-animation {
animation-play-state: paused;
animation: new-animate 10s infinite ease-in-out;
}
#keyframes new-animate{
from {
// current position
}
to {
transform: translate(500px, 20px) scale(1.5);
}
}
Javascript:
const block = document.querySelector('.block')
const image = document.querySelector('.image')
const togglenewAnimation = () => {
block.classList.toggle('new-animation');
}
image.onclick = () => togglenewAnimation();
What I am trying to do is pause the first animation, and then start the new animation based on the current position the div is located.
Any help is very much apreciated. Thank you!
I'm trying to add an animation to an element when someone hover on it.
My thought is to add a class with keyframes and attach an mouseover event listener to it.
The reason I don't use CSS is because I want the animation to be finished even the mouse leave the element before the animation is finished. For example, the mouse is moved out of element when rotating on 180 degree (full animation is 360 degree)
But sadly it's not working and I don't know why...
const item = document.querySelector('#rotate');
item.addEventListener('mouseover',function(e) {
if(item) e.classList.add('rotate');
});
#div {
width: 120px;
height: 120px;
background-color: orange;
}
.rotate {
animation: rotating 1s ease 0s 1 normal forwards;
}
#keyframes rotating {
0% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}
<div id='rotate'></div>
You're already on the right path. You can listen for the animationend event on the div and remove the rotate class when the event is fired. I've corrected your example snippet below.
const item = document.querySelector('#rotate');
item.addEventListener('mouseover', function(e) {
if(item) item.classList.add('rotate');
});
item.addEventListener('animationend', function(e) {
if(item) item.classList.remove('rotate');
});
#rotate {
width: 120px;
height: 120px;
background-color: orange;
}
.rotate {
animation: rotating 1s ease 0s 1 normal forwards;
}
#keyframes rotating {
0% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}
<div id='rotate'></div>
I would say you were pretty close. firstly you must change #div to #rotate then add the class directly to the item then when animation is done remove the class so that it can run again
const item = document.querySelector('#rotate');
item.addEventListener('mouseover', function(e) {
item.classList.add('rotate');
});
item.addEventListener('animationend', function(e) {
item.classList.remove('rotate');
});
#rotate {
width: 120px;
height: 120px;
background-color: orange;
}
.rotate {
animation: rotating 1s ease 0s 1 normal forwards;
}
#keyframes rotating {
0% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}
<div id='rotate'></div>
Doesn't change your code too much.
e refers to the event which is incorrect use of it, you should use this to target the current element
use mouseenter will be better in this sitution when you want to trigger an animation when use hover it .
const item = document.querySelector('#rotate');
item.addEventListener('mouseenter',function(e) {
if(item) this.classList.add('rotate');
});
#rotate {
width: 120px;
height: 120px;
background-color: orange;
}
.rotate {
animation: rotating 1s ease 0s 1 normal forwards;
}
#keyframes rotating {
0% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}
<div id='rotate'></div>
So basically I have a process with multiple steps that users will go through. Whenever they click a forward button, I want to slide the current step to the left and slide the next step on from right to left. When hitting backwards, I want the current step to slide off to the right and the previous step to slide in from the left. I have it working so it correctly does the slide on the first click both ways, the problem arrives when I basically try to toggle it (so clicking on forward, then back). When I do this, the thing will slide off correctly, but the previous step does not slide back on, leaving a blank content area. This is the state of the classes once you hit forward first, then hit back:
Here's my animation CSS:
#keyframes slide-in-from-left {
0% { tranform: translate(-100%); }
100% { transform: translateX(0%); }
}
#keyframes slide-out-left {
0% { transform: translateX(0%); }
100% { transform: translateX(-100%); }
}
#keyframes slide-in-from-right {
0% { transform: translateX(100%); }
100% { transform: translateX(0%); }
}
#keyframes slide-out-right {
0% { transform: translateX(0%); }
100% { transform: translateX(100%); }
}
// Animation Classes
// ------------------------------
.slide-in-from-left {
animation: slide-in-from-left 0.5s forwards;
}
.slide-out-left {
animation: slide-out-left 0.5s forwards;
}
.slide-in-from-right {
animation: slide-in-from-right 0.5s forwards;
}
.slide-out-right {
animation: slide-out-right 0.5s forwards;
}
And then I just have:
[class^="step-"] {
position: absolute;
}
.step-4 {
transform: translateX(-100%);
}
And my jQuery/coffeescript:
goForwardAStep = () ->
step = $(this).data('step')
$('.signup .step-' + step).addClass('slide-out-left')
$('.signup .step-' + (step + 1)).addClass('slide-in-from-right')
goBackAStep = () ->
step = $(this).data('step')
$('.signup .step-' + step).addClass('slide-out-right')
$('.signup .step-' + (step - 1)).addClass('slide-in-from-left')
Should I be removing a class somewhere when the steps change? Should I have more classes involved to make sure things are laying off screen where they should?
A simpler approach. 3 clases for the state:
.current {
transform: {translateX(0%);}
}
.moved-left {
transform: {translateX(-100%);}
}
.moved-right {
transform: {translateX(100%);}
}
and a permanent one
.slide {
transition: transform 0.5s;
}
I am try to have the caret in the following rotate 180 degrees on click for my dropdown menu. In the solution Im trying to implement, it changes the class of the the caret to toggle-up or toggle-down on click. The first time I click on it rotates up, the second time it immediately goes back to its starting position and then rotates back up. I smell dirty code, whats the easiest way to add this toggle rotation animation. Thanks in advance for any help. Heres my current css:
.toggle-up {
animation-name: toggle-up;
animation-delay: 0.25s;
animation-duration: 0.75s;
animation-fill-mode: forwards;
}
.toggle-down {
animation-name: toggle-down;
animation-delay: 0.25s;
animation-duration: 0.75s;
animation-fill-mode: forwards;
}
/*animations*/
#keyframes toggle-up {
100% {
transform: rotate(180deg);
}
}
#keyframes toggle-down {
100% {
transform: rotate(180deg);
}
}
You don't really need a keyframe animation for something this simple. If you just add a class to your icon on click then remove it this will apply your rotation. Here is a working plunkr using font awesome and a simple rotation. This is just a simple example, you will want to make use of vendor prefixes and be aware that css transitions do not work in older browsers.
<div id="container">
<i id="icon" class="fa fa-arrow-down"></i>
</div>
.fa-arrow-down{
transform: rotate(0deg);
transition: transform 1s linear;
}
.fa-arrow-down.open{
transform: rotate(180deg);
transition: transform 1s linear;
}
(function(document){
var div = document.getElementById('container');
var icon = document.getElementById('icon');
var open = false;
div.addEventListener('click', function(){
if(open){
icon.className = 'fa fa-arrow-down';
} else{
icon.className = 'fa fa-arrow-down open';
}
open = !open;
});
})(document);
.square {
width: 100px;
height: 100px;
background-color: #ff0000;
transition: all 0.75s 0.25s;
}
.toggle-up {
transform: rotate(180deg);
}
.toggle-down {
transform: rotate(0);
}
You should have an initial state in order to complete your animation.
Here is the example: codepen
UPDATE
Here is the version without using javascript: codepen
<label for="checkbox">
<input type="checkbox" id="checkbox">
<div class="square toggle-down"></div>
</label>
#checkbox {
display: none;
}
.square {
width: 100px;
height: 100px;
background-color: #ff0000;
transition: all 0.75s 0.25s;
transform: rotate(0);
}
#checkbox:checked + .square {
transform: rotate(180deg);
}
The general idea is to change the block class using Adjacent sibling selectors and the checkbox checked state.
I've been trying to learn css animations and I'm starting to get a grip on them but I'm having an issue an animation effect. I have an animation class assigned to a section that is a download button when I click it the animation plays for the extent of the click, if i click and hold it plays the whole animation. I want the animation to play all the way through on on click, not a click and hold.
Heres the Html section the class is applied to:
<a href="software/ASC.exe">
<section id="download" class="animated" title="Download ASC">
Download
</section>
</a>
Here is the CSS animation class:
.animated {
}
.animated:active {
-webkit-animation:fadeOutUp 2s;
-moz-animation:fadeOutUp 2s;
-o-animation:fadeOutUp 2s;
-ms-animation:fadeOutUp 2s;
animation:fadeOutUp 2s;
box-shadow:3px 1px 20px 4px #0099CC;
}
#-webkit-keyframes fadeOutUp {
0% {
opacity: 1;
-webkit-transform: translateY(0);
}
100% {
opacity: 0;
-webkit-transform: translateY(-20px);
}
}
#-moz-keyframes fadeOutUp {
0% {
opacity: 1;
-moz-transform: translateY(0);
}
100% {
opacity: 0;
-moz-transform: translateY(-20px);
}
}
#-o-keyframes fadeOutUp {
0% {
opacity: 1;
-o-transform: translateY(0);
}
100% {
opacity: 0;
-o-transform: translateY(-20px);
}
}
#keyframes fadeOutUp {
0% {
opacity: 1;
transform: translateY(0);
}
100% {
opacity: 0;
transform: translateY(-20px);
}
}
.fadeOutUp {
-webkit-animation-name: fadeOutUp;
-moz-animation-name: fadeOutUp;
-o-animation-name: fadeOutUp;
animation-name: fadeOutUp;
}
Any help is appreciated!
HTML
<a href="#" id="buttonLink">
<section id="download" class="animated" title="Download ASC">
Download
</section>
</a>
CSS
.clicked {
-webkit-animation:fadeOutUp 2s;
-moz-animation:fadeOutUp 2s;
-o-animation:fadeOutUp 2s;
-ms-animation:fadeOutUp 2s;
animation:fadeOutUp 2s;
box-shadow:3px 1px 20px 4px #0099CC;
}
JavaScript
var el = document.getElementById('buttonLink');
el.addEventListener('click', function(){
document.getElementById('download').className = 'clicked';
})
DEMO
You could do it with jQuery
DEMO http://jsfiddle.net/kevinPHPkevin/Uj5gC/1/
$("#download").click(function () {
$(this).addClass("animated1");
});
To reset the animation just remove the class after 2 seconds
DEMO http://jsfiddle.net/kevinPHPkevin/Uj5gC/4/
$("#download").click(function () {
$(this).addClass("animated1");
setInterval(function () {
$("#download").removeClass("animated1");
}, 2000);
});
** EDITED**
Just for the challenge, here's a CSS only option using :target
DEMO http://jsfiddle.net/kevinPHPkevin/Uj5gC/2/
A demo that uses javascript to add that 'animated' class. Anyone knows a way to do that from CSS (kinda' impossible though :D)? It'd be interesting. Plunk here http://plnkr.co/edit/IhkmgKQ9Od0dyb3HFuEv?p=preview
window.onload = function() {
var btn = document.getElementById("download");
btn.addEventListener("click", function(e) {
this.className = "animated";
});
}
You can archieve this in pure CSS by using :not(:active) instead of just .active.