Toggle animation on click of button using js - javascript

I'm trying to get a square to 'fold out' on click of a button -- kind of like a drop-down.
Right now I have this, but it doesn't seem to do anything...
function toggle() {
let classList = document.getElementById('box').classList;
if (classList.contains('expand')) {
classList.remove('expand');
classList.add('retract');
} else if (classList.contains('retract')) {
classList.remove('retract');
classList.add('expand');
}
}
#keyframes anim {
0%: {
visibility: hidden;
}
1%: {
visibility: visible;
max-height: 0px;
}
100%: {
visibility: visible;
max-height: 100px; /* or something bigger than we'll 'ever need' */
}
}
.expand .retract {
animation-name: anim;
animation-duration: 500ms;
animation-iteration-count: 1;
}
.expand {
animation-fill-mode: forwards;
}
.retract {
animation-direction: reverse;
animation-fill-mode: backwards;
}
#box {
background-color: red;
height: 0px;
visibility: hidden;
width: 50px;
}
<button onclick="toggle()">toggle</button>
<div id="box"></div>
Note, that I need to have visibility: hidden here!
How can I achieve this?

OK, your problem is solved. This tryit from W3Schools helped me a lot. I didn't need two class names. Also, as #tao said, there is no point in animating visibility (look at the comments below). Here is the CodePen pen with this code. I guess this is what you want, am I right?
const toggle = () => box?.classList.toggle('expand')
#box.expand {
height: 100px;
}
#box {
width: 50px;
height: 0;
overflow: hidden;
background: red;
transition: height 1s;
}
<button onclick="toggle()">toggle</button>
<div id="box"></div>

Related

How to make an image fade in and another fade out with one button click?

I'm trying to fade in the blue square with the first click of the button. And then on the second click, the blue square fades out and the red one fades in.
As you can see when you test it, it doesn't work that way. I don't know where I am wrong and If anyone can show me how to fix it I'd appreciate it.
var currentscene = 0;
function next() {
currentscene++;
if (currentscene = 1) {
var element = document.getElementById("blue");
element.classList.add("fade-in");
}
if (currentscene = 2) {
var element = document.getElementById("blue");
element.classList.add("fade-out");
var element = document.getElementById("red");
element.classList.add("fade-in");
}
}
.squareblue {
height: 50px;
width: 50px;
top: 50px;
background-color: blue;
position: absolute;
opacity: 0;
animation-fill-mode: forwards;
}
.squarered {
height: 50px;
width: 50px;
top: 100px;
background-color: red;
position: absolute;
opacity: 0;
animation-fill-mode: forwards;
}
.fade-out {
animation: fadeOut ease 2s
}
#keyframes fadeOut {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
.fade-in {
animation: fadeIn ease 2s
}
#keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
<div2 id="blue" class="squareblue"></div2>
<div2 id="red" class="squarered"></div2>
<button class="button" onclick="next()">next</button>
A few mistakes, and a few things to improve.
Inside your if conditionals, you were assigning the value of 1 and 2 to the variable currentscene instead of using the comparison operator ==. I added the remainder operator to be able to continue the loop indefinitely.
Instead of grabbing the element from the dom each loop, I just defined the elements at the top, and continued to reference the save variable.
instead of using a css keyframes animation, I used the css transition property to add animation to the changing of opacity.
If you have any questions, please ask 🚀
let currentscene = 0;
const blue = document.getElementById("blue");;
const red = document.getElementById("red");;
function next() {
currentscene++;
if (currentscene % 2 == 0) {
blue.classList.remove("opaque");
red.classList.add("opaque");
}
else if (currentscene % 2 == 1) {
red.classList.remove("opaque");
blue.classList.add("opaque");
}
}
.squareblue,
.squarered {
height: 50px;
width: 50px;
position: absolute;
opacity: 0;
animation-fill-mode: forwards;
transition: 1s;
}
.squareblue {
top: 50px;
background-color: blue;
}
.squarered {
top: 100px;
background-color: red;
}
.opaque {
opacity: 1;
}
button {user-select: none}
<div2 id="blue" class="squareblue"></div2>
<div2 id="red" class="squarered"></div2>
<button class="button" onclick="next()">next</button>

CSS transition not working when adding class via jquery

I am adding a class to show an image when the mouse is over a div, but the transition isnt working at all.
I am using opacity, I know that the visibily: hidden is not animable.
The code is in the snippet:
$(document).ready(function() {
$("#trigger").on("mouseenter", function () {
$("#imgPuffo").addClass("visible");
$("#trigger").on("mouseout", function () {
$("#imgPuffo").removeClass("visible");
});
});
});
#trigger {
height: 100px;
width: 100px;
background: red;
}
img {
opacity: 0;
animation: opacity 2s;
}
.visible {
visibility: visible;
opacity: 1;
animation: opacity 2s;
}
.imgPuffo {
height: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="trigger"></div>
<img id="imgPuffo" class="imgPuffo" src="https://www.pinclipart.com/picdir/big/449-4499911_how-to-draw-papa-smurf-from-the-smurfs.png" alt="">
There's a bit of confusion as animation is being used, but animation will look for an #keyframes sequence to tell it what animation to run. In fact it looks as though we don't need a full CSS animation in this case, just a CSS transition.
I've added transition: all 2s in case you want to transition anything else in future, like the scale, but if you just want to stick with transitioning opacity you could do transition: opacity 2s instead.
$(document).ready(function() {
$("#trigger").on("mouseenter", function () {
$("#imgPuffo").addClass("visible");
$("#trigger").on("mouseout", function () {
$("#imgPuffo").removeClass("visible");
});
});
});
#trigger {
height: 100px;
width: 100px;
background: red;
}
img {
opacity: 0;
/* animation: opacity 2s; */
transition: all 2s;
}
.visible {
visibility: visible;
opacity: 1;
/* animation: opacity 2s; */
}
.imgPuffo {
height: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="trigger"></div>
<img id="imgPuffo" class="imgPuffo" src="https://www.pinclipart.com/picdir/big/449-4499911_how-to-draw-papa-smurf-from-the-smurfs.png" alt="">
if you want to use animations check the docs. You need to use #keyframes
$(document).ready(function() {
$("#trigger").on("mouseenter", function () {
$("#imgPuffo").addClass("visible");
$("#trigger").on("mouseout", function () {
$("#imgPuffo").removeClass("visible");
});
});
});
#trigger {
height: 100px;
width: 100px;
background: red;
}
img {
opacity: 0;
animation: opacity 2s;
}
.visible {
visibility: visible;
opacity: 1;
transition: opacity 2s ease-in-out;
}
.imgPuffo {
height: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="trigger"></div>
<img id="imgPuffo" class="imgPuffo" src="https://www.pinclipart.com/picdir/big/449-4499911_how-to-draw-papa-smurf-from-the-smurfs.png" alt="">
How about a solution for css using a :hover, without jquery?
#trigger {
height: 100px;
width: 100px;
background: red;
}
#trigger:hover + .imgPuffo {
opacity: 1;
}
.imgPuffo {
opacity: 0;
height: 200px;
transition: opacity 2s;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="trigger"></div>
<img id="imgPuffo" class="imgPuffo" src="https://www.pinclipart.com/picdir/big/449-4499911_how-to-draw-papa-smurf-from-the-smurfs.png" alt="">

How to trigger CSS animation [duplicate]

This question already has answers here:
Restart animation in CSS3: any better way than removing the element?
(14 answers)
Closed 4 years ago.
I am new to CSS but do know the basics, I want to trigger this animation by using a button. I cannot get it to work.
I used a couple of examples here in Stackoverflow, Jquery, Jscript, but none seem to refer to the #keyframes .
I see more about referring to an animation via classes and removing classes (As I understand this way to restart the animation by removing the element). I tried switching it to classes.
I also then wonder what is best practise?
What is the best way? I thought it would be simple, but I was mistaken.....
I have CSS like so:
#test {
margin-left: 20px;
margin-top: 20px;
width: 50px;
height: 0px;
background: maroon;
position: absolute;
animation-name: example;
animation-duration: 3s;
animation-fill-mode: forwards;
animation-delay: 0s;
}
#keyframes example {
from { transform: translateY(200px)}
to {height: 200px; background-color: teal;}
}
I am unable to reproduce the issue you described with your CSS.
See sample below:
This answer will be deleted once the question is edited with a mcve.
Please note:
If you question is about best practices, then it'd be off-topic for StackOverflow. See our how to ask page
$(function() {
$("#test-btn").on('click', function() {
$("#test").addClass('animation');
});
});
.animation {
margin-left: 20px;
margin-top: 20px;
width: 50px;
height: 0px;
background: maroon;
position: absolute;
animation-name: example;
animation-duration: 3s;
animation-fill-mode: forwards;
animation-delay: 0s;
}
#keyframes example {
from {
transform: translateY(200px)
}
to {
height: 200px;
background-color: teal;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="test-btn">Animate</button>
<hr/>
<div id="test"></div>
In case you decide to scrap jQuery (or you have to work without it), in order to toggle the CSS animation on your #test element using vanilla JavaScript, separate your animation-related CSS properties into a class:
.animate {
animation-name: example;
animation-duration: 3s;
animation-fill-mode: forwards;
animation-delay: 0s;
}
Then toggle (add/remove) the .animate class on the #test element:
button.addEventListener('click', function() {
if (isAnimating) {
element.classList.remove('animate');
button.innerHTML = 'Add animation';
} else {
element.classList.add('animate');
button.innerHTML = 'Remove animation';
}
isAnimating = !isAnimating;
});
var element = document.getElementById('test');
var button = document.getElementById('toggle');
var isAnimating = false;
button.addEventListener('click', function() {
if (isAnimating) {
element.classList.remove('animate');
button.innerHTML = 'Add animation';
} else {
element.classList.add('animate');
button.innerHTML = 'Remove animation';
}
isAnimating = !isAnimating;
});
#test {
margin-left: 20px;
margin-top: 20px;
width: 50px;
height: 0px;
background: maroon;
position: absolute;
}
.animate {
animation-name: example;
animation-duration: 3s;
animation-fill-mode: forwards;
animation-delay: 0s;
}
#toggle {
margin-left: 100px;
}
#keyframes example {
from {
transform: translateY(200px)
}
to {
height: 200px;
background-color: teal;
}
}
<div id="test"></div>
<button id="toggle">Add animation</button>

How to control the transform distance with pure JavaScript

I made this
http://codepen.io/adamchenwei/pen/dOvJNX
and I try to apply a certain way of moving for a dom so it move for a fixed distance and stop, instead of animate and move through the whole width of the dom. However, I don't really want to fix the distance inside the css keyframe because I need to detect that distance dynamically, since my div that got animated ideally will change the width dynamically as well since that is not going always be 100% or any specific px fixed.
Is there way I can do that in JavaScript instead and not let css to take charge in this transform distance part?
Cross browser capacity will be great.
SCSS
.myItem {
height: 100px;
width: 501px;
background-color: beige;
animation: to-left-transition 300ms;
animation-iteration-count: 1;
animation-fill-mode: forwards;
animation-timing-function: ease-in-out;
}
#keyframes to-left-transition {
0% {
transform: translate(0);
}
100% {
transform: translate(100%);
}
}
HTML
<div class="myItem">
stuff here
</div>
Found out a better way. Soooooo much easier!
I should have been using transition instead of animation. As that give me the flexibility to adjust the animation accordingly.
Hope it helps someone else to save couple hours!
http://codepen.io/adamchenwei/pen/xRqYNj
HTML
<div class="myItem">
stuff here
</div>
CSS
.myItem {
position: absolute;
height: 100px;
width: 501px;
background-color: beige;
transition: transform 1s;
}
JS
setTimeout(function() {
document.getElementsByClassName('myItem')[0].style.transform="translateX(400px)";
console.log('ran');
}, 3000);
EDIT
Below is a method sugguested by Dennis Traub
setTimeout(function() {
console.log('ran');
$("head").append('<style type="text/css"></style>');
var new_stylesheet = $("head").children(':last');
new_stylesheet.html('.myItem{animation: to-left-transition 600ms;}');
}, 3000);
.myItem {
position: absolute;
height: 100px;
width: 501px;
background-color: beige;
animation-iteration-count: 1;
animation-fill-mode: forwards;
animation-timing-function: ease-in-out;
}
#keyframes to-left-transition {
0% {
transform: translate(0);
}
100% {
transform: translate(100%);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="item" class="myItem">
stuff here
</div>
Answer Before EDIT
Here is a good reference for something similar to what i think you are trying to accomplish.
Based on your dynamic input you could have a function that controls how far the div transitions. Still use your code for transition in the css, but compute how far you want in the jquery or JavaScript. Then call the css transition for how far or long you want to transition.
var boxOne = document.getElementsByClassName('box')[0],
$boxTwo = $('.box:eq(1)');
document.getElementsByClassName('toggleButton')[0].onclick = function() {
if(this.innerHTML === 'Play')
{
this.innerHTML = 'Pause';
boxOne.classList.add('horizTranslate');
} else {
this.innerHTML = 'Play';
var computedStyle = window.getComputedStyle(boxOne),
marginLeft = computedStyle.getPropertyValue('margin-left');
boxOne.style.marginLeft = marginLeft;
boxOne.classList.remove('horizTranslate');
}
}
$('.toggleButton:eq(1)').on('click', function() {
if($(this).html() === 'Play')
{
$(this).html('Pause');
$boxTwo.addClass('horizTranslate');
} else {
$(this).html('Play');
var computedStyle = $boxTwo.css('margin-left');
$boxTwo.removeClass('horizTranslate');
$boxTwo.css('margin-left', computedStyle);
}
});
.box {
margin: 30px;
height: 50px;
width: 50px;
background-color: blue;
}
.box.horizTranslate {
-webkit-transition: 3s;
-moz-transition: 3s;
-ms-transition: 3s;
-o-transition: 3s;
transition: 3s;
margin-left: 100% !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h3>Pure Javascript</h3>
<div class='box'></div>
<button class='toggleButton' value='play'>Play</button>
<h3>jQuery</h3>
<div class='box'></div>
<button class='toggleButton' value='play'>Play</button>
This code was written by Zach Saucier on codepen
This is a good reference for manipulating css with JS: https://css-tricks.com/controlling-css-animations-transitions-javascript/

How to set 0% css of keyframes as current css value for the element?

I am trying to make a progress indicator div using CSS animations. Please refer to the linked JSBin. The behavior I am trying to achieve is, when the user clicks on stage3 after stage1, the div width should increase from current 30% to 100% and not start from 0% as it is doing right now. I know if i set the 0% value as width: 30%, I can get that. But it won't work so well if I have many stages. I want the animation to start from final width of last stage to the width specified in new stage.
Progress indicator snippet
document.getElementById('stage1').addEventListener('click', function() {
document.getElementById('progress').classList.add('stage1');
}, false);
document.getElementById('stage2').addEventListener('click', function() {
document.getElementById('progress').classList.add('stage2');
}, false);
document.getElementById('stage3').addEventListener('click', function() {
document.getElementById('progress').classList.add('stage3');
}, false);
.progress-wrapper {
height: 10px;
width: 400px;
background-color: #BBDEFB;
}
#progress {
background-color: #AADE00;
height: 10px;
width: 0;
}
.stage1 {
animation-name: stage1;
animation-duration: 1s;
animation-fill-mode: forwards;
}
#keyframes stage1 {
to {
width: 30%;
}
}
.stage2 {
animation-name: stage2;
animation-duration: 1s;
animation-fill-mode: forwards;
}
#keyframes stage2 {
to {
width: 70%;
}
}
.stage3 {
animation-name: stage3;
animation-duration: 1s;
animation-fill-mode: forwards;
}
#keyframes stage3 {
to {
width: 100%;
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<div class="progress-wrapper">
<div id="progress"></div>
</div>
<pre>
</pre>
<button id="stage1">stage1</button>
<button id="stage2">stage2</button>
<button id="stage3">stage3</button>
</body>
</html>
I'm not aware of a CSS-only solution, but you could set the width of the progress element before adding the class.
In doing so, it will transition from the previous width rather than from 0.
var progress = document.getElementById('progress');
document.getElementById('stage1').addEventListener('click', function() {
setPreviousWidth();
progress.classList.add('stage1');
}, false);
document.getElementById('stage2').addEventListener('click', function() {
setPreviousWidth();
progress.classList.add('stage2');
}, false);
document.getElementById('stage3').addEventListener('click', function() {
setPreviousWidth();
progress.classList.add('stage3');
}, false);
function setPreviousWidth () {
progress.style.width = progress.offsetWidth + 'px';
}
.progress-wrapper {
height: 10px;
width: 400px;
background-color: #BBDEFB;
}
#progress {
background-color: #AADE00;
height: 10px;
width: 0;
}
.stage1 {
animation-name: stage1;
animation-duration: 1s;
animation-fill-mode: forwards;
}
#keyframes stage1 {
to {
width: 30%;
}
}
.stage2 {
animation-name: stage2;
animation-duration: 1s;
animation-fill-mode: forwards;
}
#keyframes stage2 {
to {
width: 70%;
}
}
.stage3 {
animation-name: stage3;
animation-duration: 1s;
animation-fill-mode: forwards;
}
#keyframes stage3 {
to {
width: 100%;
}
}
<div class="progress-wrapper">
<div id="progress"></div>
</div>
<pre>
</pre>
<button id="stage1">stage1</button>
<button id="stage2">stage2</button>
<button id="stage3">stage3</button>

Categories