css animation how to use “reverse” for a hover and out event?

前端 未结 2 1194
别那么骄傲
别那么骄傲 2020-12-11 12:08

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

相关标签:
2条回答
  • 2020-12-11 12:43

    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.

    0 讨论(0)
  • 2020-12-11 12:44

    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>

    0 讨论(0)
提交回复
热议问题