Can't Use the Same Animation in Reverse for Class Toggle

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 reverse

  • Use 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



Leave a reply



Submit