Como reverter uma animação ao afastar o mouse após passar o mouse

92

Portanto, é possível ter animação reversa na saída do mouse como:

.class{
   transform: rotate(0deg);

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

mas, ao usar a animação @keyframes, não consegui fazê-la funcionar, por exemplo:

.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);}
}

Qual é a solução ideal, sabendo que eu precisaria de iterações e da própria animação?

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

Khaled
fonte
Não seria melhor usar transições, como aqui - jsfiddle.net/HQFby ?
piatek
A resposta já foi postada em stackoverflow. insira a descrição do link aqui
watereffect de

Respostas:

61

Eu acho que se você tem um to, você deve usar um from. Eu pensaria em algo como:

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

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

Claro que já deve ter verificado, mas achei estranho que você só use a transformpropriedade já que CSS3 não está totalmente implementado em todos os lugares. Talvez funcionasse melhor com as seguintes considerações:

  • Chrome usa @-webkit-keyframes, nenhuma versão particular necessária
  • O Safari usa @-webkit-keyframesdesde a versão 5+
  • O Firefox usa @keyframesdesde a versão 16 (v5-15 usado @-moz-keyframes)
  • Opera usa @-webkit-keyframesversão 15-22 (apenas v12 usada @-o-keyframes)
  • O Internet Explorer usa @keyframesdesde a versão 10+

EDITAR:

Eu inventei aquele violino:

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

Usando código mínimo. Está se aproximando do que você esperava?

Xaltar
fonte
1
O IE 10 oferece suporte a animações de quadro-chave.
dlev
4
Isso reverte a transição, mas o problema é que se o mouse estiver fora antes do final da transição de foco, obtemos este "salto". Depois de alguma pesquisa, aparentemente o estado do elemento deve ser "persistido" para que possamos reverter da posição de rotação final, para aquele "modo de preenchimento de animação: para frente;" pode ser usado, mas não parece funcionar.
Khaled
24
@Xaltar Quando você carrega o aplicativo pela primeira vez, a primeira animação é reproduzida sem passar o mouse sobre o quadrado. Existe alguma maneira de impedir que a animação de carregamento inicial ocorra?
jlewkovich
3
Alguém encontrou uma solução para a primeira animação sendo reproduzida sozinha após a atualização? Meio importante.
user2619824
2
Esta resposta será inútil se você não puder suprimir a reprodução da animação pela primeira vez
NearHuscarl
23

É muito mais fácil do que tudo isso: basta fazer a transição da mesma propriedade em seu elemento

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

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

Jordan Lafland
fonte
4
Sim, mas isso só funcionará se apenas uma propriedade for alterada.
Marcus
4
@Marcustransition: border-color 0.3s, background-color 0.3s, color 0.3s;
Scoots de
4
Uau, CSS percorreu um longo caminho desde a última vez que fiz alguma programação web: D
Franz D.
5
ele está perguntando sobre animação !!
iKamy de
18

Não acho que isso seja possível usando apenas animações CSS. Estou assumindo que as transições CSS não atendem ao seu caso de uso, porque (por exemplo) você deseja encadear duas animações, usar várias paradas, iterações ou de alguma outra forma explorar as animações de poder adicionais concedidas a você.

Não encontrei nenhuma maneira de acionar uma animação CSS especificamente na saída do mouse sem usar JavaScript para anexar as classes "over" e "out". Embora você possa usar a declaração CSS básica para acionar uma animação quando o: hover terminar, a mesma animação será executada no carregamento da página. Usando as classes "over" e "out", você pode dividir a definição na declaração de base (load) e nas duas declarações de trigger de animação.

O CSS para esta solução seria:

.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);
    }
}

E usando JavaScript (sintaxe jQuery) para vincular as classes aos eventos:

$(".class").hover(
    function () {
        $(this).removeClass('out').addClass('over');
    },
    function () {
        $(this).removeClass('over').addClass('out');
    }
);
Giles Copp
fonte
10

criar uma animação reversa é um exagero para um problema simples, o que você precisa é

animation-direction: reverse

no entanto, isto não funcionará por si porque as especificações de animação são tão vazias que se esqueceram de adicionar uma forma de reiniciar a animação, então aqui está como você pode fazer isso com a ajuda de 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>

ctf0
fonte
4

Você ficaria melhor tendo apenas uma animação, mas invertida?

animation-direction: reverse
Andrew Lazarus
fonte
4
Atualmente compatível apenas com alguns navegadores
Adam Hutchinson
Tem algum exemplo?
MD Ashik
4

podemos usar requestAnimationFrame para redefinir a animação e revertê-la quando o navegador for pintado no próximo quadro.

Use também os manipuladores de eventos onmouseenter e onmouseout para inverter a direção da animação

Conforme

Quaisquer rAFs enfileirados em seus manipuladores de eventos serão executados no mesmo quadro. Quaisquer rAFs enfileirados em um rAF serão executados no próximo quadro.

function fn(el, isEnter) {
  el.className = "";
   requestAnimationFrame(() => {
    requestAnimationFrame(() => {
        el.className = isEnter? "in": "out";
    });
  });  
}
.in{
  animation: k 1s forwards;
}

.out{
  animation: k 1s forwards;
  animation-direction: reverse;
}

@keyframes k
{
from {transform: rotate(0deg);}
to   {transform: rotate(360deg);}
}
<div style="width:100px; height:100px; background-color:red" 
  onmouseenter="fn(this, true)"
   onmouseleave="fn(this, false)"  
     ></div>

Shishir Arora
fonte
0

Experimente isto:

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

compatível com Firefox 5+, IE 10+, Chrome, Safari 4+, Opera 12+

Ansipants
fonte
0

Já tentei várias soluções aqui, nada funcionou perfeitamente; então Pesquisei um pouco mais na web, para encontrar GSAP em https://greensock.com/ (sujeito a licença, mas é muito permissivo); uma vez que você faz referência ao lib ...

 <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.2.4/gsap.min.js"></script>

... você pode ir:

  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();
  });

E funcionará perfeitamente.

Razvan_TK9692
fonte
0

rsrsrs, tem uma solução muito fácil somente com CSS. Aqui está

#thing {padding: 10px; raio da borda: 5px;

/ * HOVER OFF * / -webkit-transição: preenchimento 2s; }

#thing: hover {padding: 20px; raio da borda: 15px;

/ * HOVER ON * / -webkit-transit: border-radius 2s; }

Neero
fonte
"lol" , você não leu a pergunta original. A OP já sabia como as transições funcionavam há 7 anos ou mais.
Zsolt Meszaros