Can't use the same animation in reverse for class toggle
The approach you use does not work as the element already has the animation expand
applied, through the class expanded
, so by simply call it again, by adding the class collapsed
, where the only difference is the reverse
, will not work, as they both reference the same animation.
W3 states: In order to restart an animation, it must be removed then reapplied. (https://www.w3.org/TR/css3-animations/#animations)
So the simplest way to make this work is to use 2 different animations, as shown in below sample.
To that sample I also added the animation fill mode forwards
, so it will retain the computed values set by the last keyframe encountered during execution.
Other ways, not shown here, could be:
Remove and reapply the animation, note though, for this to look good the element might need to have its end state applied initially, or else it could jump back on removal
Use
animation-play-state
and a script, to pause an animation half way, where the second half does the reverseUse
animation-timing-function
to add steps to the animation
const example = document.getElementById('example');
let expanded = false;
example.className = 'expanded';
const toogleClass = () => { example.className = expanded ? 'expanded' : 'collapsed'; expanded = !expanded;}
setInterval(toogleClass, 2500);
div { max-height: 1em; width: 50px; background-color: red; color: white; text-align: center; border-radius: 30px; padding: 1em 0;}
.expanded { animation: expand 2s forwards; background-color: blue;}
.collapsed { background-color: red; animation: collaps 2s;}
@keyframes expand { 0% { max-height: 1em; } 50% { max-height: 1em; } 100% { max-height: 200px; }}
@keyframes collaps { 0% { max-height: 200px; } 50% { max-height: 200px; } 100% { max-height: 1em; }}
<div id="example"> Hello <br> <br> <br> <br> Friends</div>
Possible to reverse a css animation on class removal?
I would have the #item
start out hidden with the reverse animation by default. Then add the class to give it the animation and show the #item
. http://jsfiddle.net/bmh5g/12/
$('#trigger').on({
mouseenter: function() {
$('#item').show();
$('#item').addClass('flipped');
},
mouseleave: function() {
$('#item').removeClass('flipped');
}
});
#trigger {
position: relative;
display: inline-block;
padding: 5px 10px;
margin: 0 0 10px 0;
background: teal;
color: white;
font-family: sans-serif;
}
#item {
position: relative;
height: 100px;
width: 100px;
background: red;
display: none;
-webkit-transform: perspective(350px) rotateX(-90deg);
transform: perspective(350px) rotateX(-90deg);
-webkit-transform-origin: 50% 0%;
transform-origin: 50% 0%;
animation: flipperUp 0.7s;
animation-fill-mode: forwards;
-webkit-animation: flipperUp 0.7s;
-webkit-animation-fill-mode: forwards;
}
#item.flipped {
animation: flipper 0.7s;
animation-fill-mode: forwards;
-webkit-animation: flipper 0.7s;
-webkit-animation-fill-mode: forwards;
}
@keyframes flipper {
0% {
transform: perspective(350px) rotateX(-90deg);
}
33% {
transform: perspective(350px) rotateX(0deg);
}
66% {
transform: perspective(350px) rotateX(10deg);
}
100% {
transform: perspective(350px) rotateX(0deg);
}
}
@-webkit-keyframes flipper {
0% {
-webkit-transform: perspective(350px) rotateX(-90deg);
}
33% {
-webkit-transform: perspective(350px) rotateX(0deg);
}
66% {
-webkit-transform: perspective(350px) rotateX(10deg);
}
100% {
-webkit-transform: perspective(350px) rotateX(0deg);
}
}
@keyframes flipperUp {
0% {
transform: perspective(350px) rotateX(0deg);
}
33% {
transform: perspective(350px) rotateX(10deg);
}
66% {
transform: perspective(350px) rotateX(0deg);
}
100% {
transform: perspective(350px) rotateX(-90deg);
}
}
@-webkit-keyframes flipperUp {
0% {
-webkit-transform: perspective(350px) rotateX(0deg);
}
33% {
-webkit-transform: perspective(350px) rotateX(10deg);
}
66% {
-webkit-transform: perspective(350px) rotateX(0deg);
}
100% {
-webkit-transform: perspective(350px) rotateX(-90deg);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<div id='trigger'>Hover Me</div>
<div id='item'></div>
Toggle a reverse animation when a button is clicked the second time
Your issue is that you are trying to animate between display: none
and display: block
which doesn't work. You need to hide the element in some other manner, like a negative offset, and then animate it to be visible.
Modify your .dropdown-meniu-content
rule to start offscreen and to have a transition
property. Then have .show
reset the transform
back to translateX(0%)
:
function myFunction(x) { x.classList.toggle("change"); document.getElementById("myDropdown").classList.toggle("show");}
html,body { margin: 0px; padding: 0px; max-width: 100%;}
.wrapper { height: 110px; width: 100%; max-width: 10000px; background-color: rgb(206, 206, 206, 0.2);}
.logo { float: left; margin-top: 10px; margin-left: 5px; width: 200px; height: 100px;}
.meniu { float: right; width: auto;}
.buton-meniu { display: block; cursor: pointer; width: 35px; margin-right: 30px; margin-top: 40px;}
.bar1,.bar2,.bar3 { width: 35px; height: 5px; background-color: #333; margin: 6px 0; transition: 0.4s;}
.change .bar1 { -webkit-transform: rotate(-45deg) translate(-9px, 6px); transform: rotate(-45deg) translate(-9px, 6px);}
.change .bar2 { opacity: 0;}
.change .bar3 { -webkit-transform: rotate(45deg) translate(-8px, -8px); transform: rotate(45deg) translate(-8px, -8px);}
.dropdown-meniu { position: relative; display: inline-block;}
.dropdown-meniu-content { top: 110px; position: fixed; background-color: #696969; width: 30%; max-width: 10000px; height: 100%; box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2); z-index: 1; overflow: hidden; right: 0; transform: translateX(100%); transition: transform 1s ease; animation-name: slideIn-meniu; -webkit-animation-duration: 0.6s; -webkit-animation-name: slideIn-meniu; animation-duration: 0.75s;}
@keyframes slideIn-meniu { from { transform: translateX(100%); opacity: 0.5; } to { margin-right: 0px; opacity: 1; }}
.show { transform: translateX(0%);}
<div class="meniu"> <div class="dropdown-meniu"> <div class="buton-meniu" onclick="myFunction(this)"> <div class="bar1"></div> <div class="bar2"></div> <div class="bar3"></div> </div> <div id="myDropdown" class="dropdown-meniu-content"> <p>TEST </p> </div> </div> </div>
How can I play the full animation of a class that was toggled in Javascript using .toggleClass?
I used simple transform
to do this animation. Kindly check the below snippet.
function onClick(){
var elem = document.getElementsByClassName('navTrigger')[0];
elem.classList.toggle('active');
}
a {
background-color: #000;
color: #fff;
display: block;
height: 200px;
}
.navTrigger {
cursor: pointer;
display: block;
width: 20px;
height: 44px;
display: flex;
flex-direction: column;
justify-content: space-around;
margin-left: 15px;
}
.navTrigger i {
background: white;
content: "";
display: block;
width: 100%;
height: 1px;
transition: all 0.3s ease;
}
.navTrigger i:nth-child(1) {
transform: translate(0, 10px);
}
.navTrigger.active i:nth-child(1) {
transform: rotate(45deg) translate(15px, 15px);
}
.navTrigger.active i:nth-child(2) {
transform: rotate(-45deg) translate(0px, 0px);
}
<a onclick="onClick()">
<span class='navTrigger inactive'>
<i></i>
<i ></i>
</span>
</a>
Why does `animation-direction: reverse` not work for my CSS keyframe animation?
Very good question. You have already noticed that animation-direction: reverse;
does work. You where very close to figuring out this css quirkiness all by yourself.
There are some additional rules to take note off.
- When removing/replacing a css animation, the animation will start from 0%,
- When you set
reverse
(while not changing the actual animation), the animation will continue from whatever % it was at.
So when you clicked the element and set the line-out
animation:
- The animation will start from 0%
- Play in whatever direction you've set.
When only applying a new animation direction:
- The animation continous from whatever percentage it was, eg, 100%.
You can restart the animation with several forms of trickery. you'll see that the animation is being played in reverse when the element is recreated.
var clickFunc =function(e) { //toggle the state $(this).toggleClass("active"); //reset the animatino state by cloning and replacing the element. var newone = this.cloneNode(true); this.parentNode.replaceChild(newone, this); // reapply click handler to the cloned element $(newone).click(clickFunc) }
$(function() { $(".question").click(function() { $(this).toggleClass("active"); }); $(".answer").click(clickFunc);
$(".restart").click(function() { $(".line").each(function() { var newone = this.cloneNode(true); this.parentNode.replaceChild(newone, this); }); });});
@keyframes line-in { 0% { transform: translateY(-45px); } 50% { transform: translateY(0); } 100% { transform: rotate(-135deg); }}@keyframes line-out { 0% { transform: rotate(-135deg); } 50% { transform: translateY(0); } 100% { transform: translateY(-45px); }}.line { width: 100%; height: 10%; position: absolute; top: 45%; background-color: orange; animation-direction: normal; animation-name: line-in; animation-duration: 1s; animation-fill-mode: forwards;}
.container { margin: 1rem auto 0; width: 100px; height: 100px; position: relative; border: 1px solid black;}.container.reverse .line { animation-name: line-in; animation-direction: reverse;}.container.active .line { animation-name: line-in; animation-direction: reverse;}.container.active.reverse .line { animation-name:line-in; animation-direction: normal;}
.container.out.active .line { animation-name: line-out; animation-direction: normal;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><button class="restart">reset animation state</button><br>in -out<div class="container question out"> <div class="line"></div></div>
active reversed<div class="container question"> <div class="line"></div></div>
<br>
workaround<div class="container answer reverse"> <div class="line"></div></div>
CSS Animation: how to trigger the reverse animation?
Your approach with margin and width to fake a rotation is very interesting, but you can do this much more simply with rotateY
.cards {
width: 800px;
margin:auto;
-webkit-perspective:1000;
}
.card {
width: 200px;
height: 100px;
position: relative;
display: inline-block;
margin: 10px;
-webkit-transition: 1s ease-in;
-webkit-transform-style: preserve-3d;
-webkit-transform:translateZ(1px);
}
.card .frontpage, .card .rearpage, img {
width: 100%;
height: 100%;
position: absolute;
top:0;
left:0;
-webkit-transform-style: preserve-3d;
-webkit-backface-visibility: hidden;
}
.card img {
width: 100%;
height: 100%;
}
.card .rearpage,
.card.opened {
-webkit-transform:rotateY(180deg);
}
Demo
As for the question you asked, you can play animations backwards by using the animation-direction:backwards
property, though with CSS toggling animations is hard. Thus, I'd recommend you use a transition
instead since it's only a change between two states.
And FYI just in case, CSS selector don't always have to be in the parent child
format. In your case applying just .child
will do the same. The parent child
selector is only necessary when needing to a higher selector specificity than existing properties.
Oh, and also FYI, jQuery isn't needed for this. I included an (untested) javascript equivalent if you want. If this is the only place where you're using jQuery on your page I'd recommend not using it because loading the whole jQuery library takes some time and data.
dropdown animation won't play in reverse after burger lines toggled again
Your problem is with the .nav opacity, when you toggle the class it goes to 0 and the menu disappears
Related Topics
Why Doesn't CSS-Calc() Work When Using 0 Inside the Equation
What Throws Internet Explorer into Quirks Mode
Sass Extend and Parent Selector
Create Clip-Path Wave CSS Edges
CSS Doesn't Work on Https Pages in Chrome and Ie
Right Border of the Addthis Counter Missing with Twitter's Bootstrap 3
Css: Auto Height on Containing Div, 100% Height on Background Div Inside Containing Div
CSS Variables - Swapping Values
How to Override Max-Width for Specific Div
How to Create Vertical Text Using Only CSS
How to Remove the Underline of a Link in Chrome Using CSS
CSS - Calc() on Font-Size - Changing Font Size Based on Container Size