How to reverse an animation on mouse out after hov

2019-01-03 15:31发布

So, it is possible to have reverse animation on mouse out such as:

.class{
   transform: rotate(0deg);

}
.class:hover{
   transform: rotate(360deg);
}

but, when using @keyframes animation, I couldn't get it to work, e.g:

.class{
   animation-name: out;
   animation-duration:2s;

}
.class:hover{
   animation-name: in;
   animation-duration:5s;
   animation-iteration-count:infinite;

}
@keyframe in{
    to {transform: rotate(360deg);}
}

@keyframe out{
    to {transform: rotate(0deg);}
}

What is the optimal solution, knowing that I'd need iterations and animation itself?

http://jsfiddle.net/khalednabil/eWzBm/

6条回答
Explosion°爆炸
2楼-- · 2019-01-03 15:49

creating a reversed animation is kinda an overkill to a simple problem, what u need is

animation-direction: reverse

however this wont work on its own because animation spec is so dump that they forgot to add a way to restart the animation so here is how you do it with the help of js

let item = document.querySelector('.item')

// play normal
item.addEventListener('mouseover', () => {
  item.classList.add('active')
})

// play in reverse
item.addEventListener('mouseout', () => {
  item.style.opacity = 0 // avoid showing the init style while switching the 'active' class

  item.classList.add('in-active')
  item.classList.remove('active')

  // force dom update
  setTimeout(() => {
    item.classList.add('active')
    item.style.opacity = ''
  }, 5)

  item.addEventListener('animationend', onanimationend)
})

function onanimationend() {
  item.classList.remove('active', 'in-active')
  item.removeEventListener('animationend', onanimationend)
}
@keyframes spin {
  0% {
    transform: rotateY(0deg);
  }
  100% {
    transform: rotateY(180deg);
  }
}

div {
  background: black;
  padding: 1rem;
  display: inline-block;
}

.item {
  /* because span cant be animated */
  display: block;
  color: yellow;
  font-size: 2rem;
}

.item.active {
  animation: spin 1s forwards;
  animation-timing-function: ease-in-out;
}

.item.in-active {
  animation-direction: reverse;
}
<div>
  <span class="item">ABC</span>
</div>

查看更多
我只想做你的唯一
3楼-- · 2019-01-03 15:50

I think that if you have a to, you must use a from. I would think of something like :

@keyframe in {
    from: transform: rotate(0deg);
    to: transform: rotate(360deg);
}

@keyframe out {
    from: transform: rotate(360deg);
    to: transform: rotate(0deg);
}

Of course must have checked it already, but I found strange that you only use the transform property since CSS3 is not fully implemented everywhere. Maybe it would work better with the following considerations :

  • Chrome uses @-webkit-keyframes, no particuliar version needed
  • Safari uses @-webkit-keyframes since version 5+
  • Firefox uses @keyframes since version 16 (v5-15 used @-moz-keyframes)
  • Opera uses @-webkit-keyframes version 15-22 (only v12 used @-o-keyframes)
  • Internet Explorer uses @keyframes since version 10+

EDIT :

I came up with that fiddle :

http://jsfiddle.net/JjHNG/35/

Using minimal code. Is it approaching what you were expecting ?

查看更多
爱情/是我丢掉的垃圾
4楼-- · 2019-01-03 15:50

I don't think this is achievable using only CSS animations. I am assuming that CSS transitions do not fulfil your use case, because (for example) you want to chain two animations together, use multiple stops, iterations, or in some other way exploit the additional power animations grant you.

I've not found any way to trigger a CSS animation specifically on mouse-out without using JavaScript to attach "over" and "out" classes. Although you can use the base CSS declaration trigger an animation when the :hover ends, that same animation will then run on page load. Using "over" and "out" classes you can split the definition into the base (load) declaration and the two animation-trigger declarations.

The CSS for this solution would be:

.class {
    /* base element declaration */
}
.class.out {
   animation-name: out;
   animation-duration:2s;

}
.class.over {
   animation-name: in;
   animation-duration:5s;
   animation-iteration-count:infinite;
}
@keyframes in {
    from {
        transform: rotate(0deg);
    }
    to {
        transform: rotate(360deg);
    }
}
@keyframes out {
    from {
        transform: rotate(360deg);
    }
    to {
        transform: rotate(0deg);
    }
}

And using JavaScript (jQuery syntax) to bind the classes to the events:

$(".class").hover(
    function () {
        $(this).removeClass('out').addClass('over');
    },
    function () {
        $(this).removeClass('over').addClass('out');
    }
);
查看更多
我命由我不由天
5楼-- · 2019-01-03 16:00

Its much easier than all this: Simply transition the same property on your element

.earth { width:  0.92%;    transition: width 1s;  }
.earth:hover { width: 50%; transition: width 1s;  }

https://codepen.io/lafland/pen/MoEaoG

查看更多
叛逆
6楼-- · 2019-01-03 16:03

Would you be better off having just the one animation, but having it reverse?

animation-direction: reverse
查看更多
一纸荒年 Trace。
7楼-- · 2019-01-03 16:08

Try this:

@keyframe in {
from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}
@keyframe out {
from {
    transform: rotate(360deg);
  }
  to {
    transform: rotate(0deg);
  }
}

supported in Firefox 5+, IE 10+, Chrome, Safari 4+, Opera 12+

查看更多
登录 后发表回答