2

Given this code (http://jsfiddle.net/bzf1mkx5/)

.intern {
    -webkit-animation: in 1s 1 reverse forwards;
}

.intern:hover {
    -webkit-animation: in 1s 1 normal forwards;
}

@-webkit-keyframes in {
    from   { -webkit-transform: scale(1); }
    to { -webkit-transform: scale(1.2);}
}
<div style = "width : 100px; height : 100px; background-color : red" class ="intern"></div>

Why are animations absent? Where is the mistake?

EDIT: By using two separated animations it does work, but then what's the point of having a reverse property?

.intern {
    -webkit-animation: in2 1s 1 reverse forwards;
}

.intern:hover {
    -webkit-animation: in 1s 1 normal forwards;
}

@-webkit-keyframes in {
    from   { -webkit-transform: scale(1); }
    to { -webkit-transform: scale(1.2);}
}
@-webkit-keyframes in2 {
    from   { -webkit-transform: scale(1); }
    to { -webkit-transform: scale(1.2);}
}
<div style = "width : 100px; height : 100px; background-color : red" class ="intern"></div>

EDIT2: If I use higher times, I should see the animations even though I will see the unwanted effect of jumping from one state to the another

.intern {
    -webkit-animation: in 20s 1 reverse forwards;
}

.intern:hover {
    -webkit-animation: in 20s 1 normal forwards;
}

@-webkit-keyframes in {
    from   { -webkit-transform: scale(1); }
    to { -webkit-transform: scale(4);}
}
<div style = "width : 50px; height : 50px; background-color : red" class ="intern"></div>

10
  • 1
    Since you have a pretty simple animation, you could simplify this an just use a transition, which will reverse automatically.
    – DBS
    Commented Aug 2, 2019 at 15:39
  • Yes I know, I just want to understand why this "animation" code fails
    – GWorking
    Commented Aug 2, 2019 at 15:40
  • for the explanation see here: stackoverflow.com/a/51221329/8620333 Commented Aug 2, 2019 at 15:48
  • another related question showing unexpected behavior when changing the duration: stackoverflow.com/q/56328415/8620333 (almost same logic as changing the direction) Commented Aug 2, 2019 at 15:53
  • Thanks, both links refer (that's what I've understood) to the problem when the first animation has not reached its end, this is not the case here, but that there is no animation at all, why is that?
    – GWorking
    Commented Aug 2, 2019 at 15:55

3 Answers 3

6

Let's first understand what reverse mean

The animation plays backwards each cycle. In other words, each time the animation cycles, the animation will reset to the end state and start over again. Animation steps are performed backwards, and timing functions are also reversed. For example, an ease-in timing function becomes ease-out. ref

Let's take a basic example to understand:

.box {
  width:50px;
  height:50px;
  margin:5px;
  background:red;
  position:relative;
}
.normal {
  animation: move normal  2s linear forwards;
}
.reverse {
  animation: move reverse 2s linear forwards;
}

@keyframes move{
  from {
    left:0;
  }
  to {
    left:300px;
  }
}
<div class="box normal">

</div>

<div class="box reverse">

</div>

We have one animation and the first element is runnig it forwards while the second element is running it backwards. Technically, it's like we invert the from and to. reverse is useful in order to avoid defining a new animation in the opposite direction. We define a left-to-right animation and with reverse we have the right-to-left one. Until now, it's trivial.

Now, if you run any kind of animation defined by its name and in the road you modify a property of this animation you will change the behavior of the whole animation and we calculate again the value of the current state based on the new animation.

Example:

.box {
  width:50px;
  height:30px;
  margin:5px;
  background:red;
  position:relative;
}
.normal,
.special{
  animation: move normal  20s linear forwards;
  background:blue;
}
.reverse,
div:hover .special{
  animation: move reverse 20s linear forwards;
  background:green;
}

@keyframes move{
  from {
    left:0;
  }
  to {
    left:300px;
  }
}

p {
 margin:0;
}
<p>Reference</p>
<div class="box normal"></div>

<div class="box reverse"></div>
<p>Hover the element</p>
<div>
   <div class="box special"></div> 
</div>

We have 3 elements animating using the same animation at the same time so they will all be at the same progress. The third one is the same as the first animation and on hover it become the same as the second one. The trick is here! on hover you will not consider the actual position of the element and simply move in the other direction but you will consider the new animation defined by reverse and calculate the value of left considering the actual progress of the animation.

If the element is at 5s of the animation in the normal state we will have left:100px and in the reverse state we will have left:200px so if you hover at 5s you will toggle between 100px and 200px. You will not consider left:100px and move back to the 0px

Now it clear that if the animation is over, you will simply toggle between the first and the last state. You will not trigger a new animation again since we are dealing with the same animation and we simply changed one setting (the direction)

.box {
  width:50px;
  height:30px;
  margin:5px;
  background:red;
  position:relative;
}
.normal,
.special{
  animation: move normal  1s linear forwards;
  background:blue;
}
.reverse,
div:hover .special{
  animation: move reverse 1s linear forwards;
  background:green;
}

@keyframes move{
  from {
    left:0;
  }
  to {
    left:300px;
  }
}

p {
 margin:0;
}
<p>Reference</p>
<div class="box normal"></div>

<div class="box reverse"></div>
<p>Hover the element</p>
<div>
   <div class="box special"></div> 
</div>


Same logic happen if you change any other property. You will not see an intuitive result because you need to imagine how the new animation will be in order to identify how the current state will become.

Example if we change the timing-function

.box {
  width:50px;
  height:30px;
  margin:5px;
  background:red;
  position:relative;
}
.normal,
.special{
  animation: move  20s linear forwards;
  background:blue;
}
.reverse,
div:hover .special{
  animation: move 20s ease forwards;
  background:green;
}

@keyframes move{
  from {
    left:0;
  }
  to {
    left:300px;
  }
}

p {
 margin:0;
}
<p>Reference</p>
<div class="box normal"></div>

<div class="box reverse"></div>
<p>Hover the element</p>
<div>
   <div class="box special"></div> 
</div>

Example if we change the duration:

.box {
  width:50px;
  height:30px;
  margin:5px;
  background:red;
  position:relative;
}
.normal,
.special{
  animation: move  20s linear forwards;
  background:blue;
}
.reverse,
div:hover .special{
  animation: move 30s linear forwards;
  background:green;
}

@keyframes move{
  from {
    left:0;
  }
  to {
    left:300px;
  }
}

p {
 margin:0;
}
<p>Reference</p>
<div class="box normal"></div>

<div class="box reverse"></div>
<p>Hover the element</p>
<div>
   <div class="box special"></div> 
</div>


What you are looking for can be achieved with transition because transition will only care about the current value and will transition to a new one when you want (on hover for example)

.intern {
  width: 100px;
  height: 100px;
  margin:50px;
  background-color: red;
  transition:10s all;
  
}

.intern:hover {
  transform:scale(4);
}
<div style="" class="intern"></div>

When you hover you will start a scale animation that will last 10s BUT if you unhover before you will get back to the initial state. You cannot do this with animation. An animation need to either run fully or you abruptly cancel it in the middle and you get back to initial state

Even if you define two animation you will not always have the needed result in you hover when the running one is not yet over. You will cancel it and run the new one.

.intern {
  width: 100px;
  height: 100px;
  margin:50px;
  background-color: red;
  animation:in 5s linear forwards; 
}

.intern:hover {
  animation:out 5s linear forwards;
}

@keyframes in {
  from {
    transform:scale(1);
  }
  to {
    transform:scale(4);
  }
}
@keyframes out {
  from {
    transform:scale(4);
  }
  to {
    transform:scale(1);
  }
}
<div style="" class="intern"></div>

Try to hover/unhover rapidly and you will see the bad effect. You will only have a perfect result if you hover at the end of each animation.

1
  • 1
    Excellent! Thanks, I have added a third snippet in the question that indeed shows what you say, I tried this before (when you said so in the comments) but I didn't notice the effect, now I've added more extreme values and it is clear that the root of the problem is what you say and what the two links said. Thanks a lot for the long and detailed explanation, I know that with transition it can be done effortless, but I wanted to understand the non-redundancy between the two :)
    – GWorking
    Commented Aug 3, 2019 at 5:24
0

You have to set the transform as a property as well:

.intern {
  -webkit-transform: scale(1);
  -webkit-animation: in 1s infinite reverse forwards;
}

.intern:hover {
  -webkit-animation: in 1s infinite normal forwards;
}

@-webkit-keyframes in {
  from {
    -webkit-transform: scale(1);
  }
  to {
    -webkit-transform: scale(1.2);
  }
}
<div style="width : 100px; height : 100px; background-color : red" class="intern"></div>

Edit: To have a simple effect, you can use transitions instead of keyframes.

.intern {
  width: 100px;
  height: 100px;
  background-color: red;
  transform: scale(1);
  transition: transform 1s;
}

.intern:hover {
  transform: scale(1.2);
}
<div class="intern"></div>

7
  • 3
    Oh pretty heartbeat!
    – Flo
    Commented Aug 2, 2019 at 15:41
  • I'm just trying in fiddle and doesn't make a difference (?)
    – GWorking
    Commented Aug 2, 2019 at 15:42
  • Have you tried exactly the code above? Note the iteration count as infinite instead of 1 Commented Aug 2, 2019 at 15:44
  • I didn't notice, it doesn't have to be infinite but only a single time, otherwise what utility has the hover event?
    – GWorking
    Commented Aug 2, 2019 at 15:46
  • @GWorking Edited my answer to include your query. Commented Aug 2, 2019 at 15:49
0

If you need the additional features CSS animations provide over transitions, there is a fix to seamlessly reverse CSS animations using the vanilla javascript Web Animations API and the playbackRate property. Check this post:

https://stackoverflow.com/a/76425356/22037119

1
  • 1
    While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - From Review Commented Jun 11, 2023 at 14:30

Not the answer you're looking for? Browse other questions tagged or ask your own question.