Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't use the same animation in reverse for class toggle

Tags:

css

I have a CSS3 animation that I want to use both in normal and reverse order. I want to trigger the animation by toggling two classes. Basically is an animation that makes an element grow, and I want to use it to shrink the element too.

Basically it is:

  • add expanded class: execute animation
  • Remove expanded class, add collapsed class: execute animation in reverse

The first part works correctly, however if I try to use the same animation for both classes the animation stops working, nothing happens.

div {
  max-height: 1em;
  width: 50px;
  background-color: red;
  color: white;
  text-align: center;
  border-radius: 30px;
  padding: 1em 0;
}

.expanded {
  animation: expand 2s;
  background-color: blue;
}

.collapsed {
  background-color: red;
  //animation: expand 2s reverse; // Uncomment and all animations stop working
}

@keyframes expand {
  0% {
    max-height: 1em;
  }
  50% {
    max-height: 1em;
  }
  100% {
    max-height: 200px;
  }
}

Here is a simple jsfiddle that demonstrates this: https://jsfiddle.net/danielo515/jxLcoocs/6/

EDIT:

As @LGSon have suggested using a transition property will be simpler for this case example, but I need to use an animation because I am running several animations and I need to be able to delay some parts of them.

like image 856
Danielo515 Avatar asked Sep 01 '25 22:09

Danielo515


1 Answers

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>

Another approach would be to use transition instead, which will give you a much simpler code

const example = document.getElementById('example');

let expanded = false;

setTimeout(function() {example.className = 'expanded';}, 500);

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;
  transition: max-height 2s;
}

.expanded {
  background-color: blue;
  max-height: 200px;
}
<div id="example">
  Hello
  <br>
  <br>
  <br>
  <br> Friends
</div>
like image 142
Asons Avatar answered Sep 03 '25 13:09

Asons