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?
we can use requestAnimationFrame to reset animation and reverse it when browser paints in next frame.
Also use onmouseenter and onmouseout event handlers to reverse animation direction
Any rAFs queued in your event handlers will be executed in the ?same frame?. Any rAFs queued in a rAF will be executed in the next frame?.
function fn(el, isEnter) {_x000D_
el.className = "";_x000D_
requestAnimationFrame(() => {_x000D_
requestAnimationFrame(() => {_x000D_
el.className = isEnter? "in": "out";_x000D_
});_x000D_
}); _x000D_
}
_x000D_
.in{_x000D_
animation: k 1s forwards;_x000D_
}_x000D_
_x000D_
.out{_x000D_
animation: k 1s forwards;_x000D_
animation-direction: reverse;_x000D_
}_x000D_
_x000D_
@keyframes k_x000D_
{_x000D_
from {transform: rotate(0deg);}_x000D_
to {transform: rotate(360deg);}_x000D_
}
_x000D_
<div style="width:100px; height:100px; background-color:red" _x000D_
onmouseenter="fn(this, true)"_x000D_
onmouseleave="fn(this, false)" _x000D_
></div>
_x000D_
Would you be better off having just the one animation, but having it reverse?
animation-direction: reverse
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+
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; }
lol, it has a very easy solution with CSS only. Here you go
#thing { padding: 10px; border-radius: 5px;
/* HOVER OFF */ -webkit-transition: padding 2s; }
#thing:hover { padding: 20px; border-radius: 15px;
/* HOVER ON */ -webkit-transition: border-radius 2s; }
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')_x000D_
_x000D_
// play normal_x000D_
item.addEventListener('mouseover', () => {_x000D_
item.classList.add('active')_x000D_
})_x000D_
_x000D_
// play in reverse_x000D_
item.addEventListener('mouseout', () => {_x000D_
item.style.opacity = 0 // avoid showing the init style while switching the 'active' class_x000D_
_x000D_
item.classList.add('in-active')_x000D_
item.classList.remove('active')_x000D_
_x000D_
// force dom update_x000D_
setTimeout(() => {_x000D_
item.classList.add('active')_x000D_
item.style.opacity = ''_x000D_
}, 5)_x000D_
_x000D_
item.addEventListener('animationend', onanimationend)_x000D_
})_x000D_
_x000D_
function onanimationend() {_x000D_
item.classList.remove('active', 'in-active')_x000D_
item.removeEventListener('animationend', onanimationend)_x000D_
}
_x000D_
@keyframes spin {_x000D_
0% {_x000D_
transform: rotateY(0deg);_x000D_
}_x000D_
100% {_x000D_
transform: rotateY(180deg);_x000D_
}_x000D_
}_x000D_
_x000D_
div {_x000D_
background: black;_x000D_
padding: 1rem;_x000D_
display: inline-block;_x000D_
}_x000D_
_x000D_
.item {_x000D_
/* because span cant be animated */_x000D_
display: block;_x000D_
color: yellow;_x000D_
font-size: 2rem;_x000D_
}_x000D_
_x000D_
.item.active {_x000D_
animation: spin 1s forwards;_x000D_
animation-timing-function: ease-in-out;_x000D_
}_x000D_
_x000D_
.item.in-active {_x000D_
animation-direction: reverse;_x000D_
}
_x000D_
<div>_x000D_
<span class="item">ABC</span>_x000D_
</div>
_x000D_
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');
}
);
Using transform in combination with transition works flawlessly for me:
.ani-grow {
-webkit-transition: all 0.5s ease;
-moz-transition: all 0.5s ease;
-o-transition: all 0.5s ease;
-ms-transition: all 0.5s ease;
transition: all 0.5s ease;
}
.ani-grow:hover {
transform: scale(1.01);
}
Have tried several solutions here, nothing worked flawlessly; then Searched the web a bit more, to find GSAP at https://greensock.com/ (subject to license, but it's pretty permissive); once you reference the lib ...
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.2.4/gsap.min.js"></script>
... you can go:
var el = document.getElementById('divID');
// create a timeline for this element in paused state
var tl = new TimelineMax({paused: true});
// create your tween of the timeline in a variable
tl
.set(el,{willChange:"transform"})
.to(el, 1, {transform:"rotate(60deg)", ease:Power1.easeInOut});
// store the tween timeline in the javascript DOM node
el.animation = tl;
//create the event handler
$(el).on("mouseenter",function(){
//this.style.willChange = 'transform';
this.animation.play();
}).on("mouseleave",function(){
//this.style.willChange = 'auto';
this.animation.reverse();
});
And it will work flawlessly.
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 :
@-webkit-keyframes
, no particuliar version needed@-webkit-keyframes
since version 5+@keyframes
since version 16 (v5-15 used @-moz-keyframes
)@-webkit-keyframes
version 15-22 (only v12 used @-o-keyframes
)@keyframes
since version 10+EDIT :
I came up with that fiddle :
Using minimal code. Is it approaching what you were expecting ?
Source: Stackoverflow.com