web-dev-qa-db-fra.com

Comment re-déclencher une animation CSS WebKit via JavaScript?

Donc, j'ai ceci -webkit-animation règle:

@-webkit-keyframes shake {
    0% {
        left: 0;
    }
    25% {
        left: 12px;
    }
    50% {
        left: 0;
    }
    75% {
        left: -12px;
    }
    100% {
        left:0;
    }
}

Et quelques CSS définissant certaines des règles d’animation sur mon box:

#box{
    -webkit-animation-duration: .02s;
    -webkit-animation-iteration-count: 10;
    -webkit-animation-timing-function: linear;
}

Je peux shake le #box comme ça:

document.getElementById("box").style.webkitAnimationName = "shake";

Mais je ne peux plus le secouer plus tard.

Cela secoue la boîte une seule fois:

someElem.onclick = function(){
    document.getElementById("box").style.webkitAnimationName = "shake";
}

Comment puis-je réactiver une animation CSS via JavaScript sans utiliser de délais d'expiration ou de multiples animations?

74
David Murdoch

J'ai trouvé la réponse basée sur le code source et des exemples à la page page des tests de transition CSS3 github .

Fondamentalement, les animations CSS ont un événement animationEnd qui est déclenché à la fin de l'animation.

Pour les navigateurs Webkit, cet événement est nommé "webkitAnimationEnd". Ainsi, pour réinitialiser une animation après son appel, vous devez ajouter un écouteur d'événement à l'élément pour l'événement animationEnd.

En plain vanilla javascript:

var element = document.getElementById('box');

element.addEventListener('webkitAnimationEnd', function(){
    this.style.webkitAnimationName = '';
}, false);

document.getElementById('button').onclick = function(){
    element.style.webkitAnimationName = 'shake';
    // you'll probably want to preventDefault here.
};

et avec jQuery:

var $element = $('#box').bind('webkitAnimationEnd', function(){
    this.style.webkitAnimationName = '';
});

$('#button').click(function(){
    $element.css('webkitAnimationName', 'shake');
    // you'll probably want to preventDefault here.
});

Le code source de tests de transition CSS (mentionné ci-dessus) contient l'objet support qui peut être utile pour les transitions CSS, les transformations et les animations entre navigateurs.

Voici le code de support (reformaté):

var css3AnimationSupport = (function(){
    var div = document.createElement('div'),
        divStyle = div.style,
        // you'll probably be better off using a `switch` instead of theses ternary ops
        support = {
            transition:
                divStyle.MozTransition     === ''? {name: 'MozTransition'   , end: 'transitionend'} :
                // Will ms add a prefix to the transitionend event?
                (divStyle.MsTransition     === ''? {name: 'MsTransition'    , end: 'msTransitionend'} :
                (divStyle.WebkitTransition === ''? {name: 'WebkitTransition', end: 'webkitTransitionEnd'} :
                (divStyle.OTransition      === ''? {name: 'OTransition'     , end: 'oTransitionEnd'} :
                (divStyle.transition       === ''? {name: 'transition'      , end: 'transitionend'} :
                false)))),
            transform:
                divStyle.MozTransform     === '' ? 'MozTransform'    :
                (divStyle.MsTransform     === '' ? 'MsTransform'     :
                (divStyle.WebkitTransform === '' ? 'WebkitTransform' : 
                (divStyle.OTransform      === '' ? 'OTransform'      :
                (divStyle.transform       === '' ? 'transform'       :
                false))))
            //, animation: ...
        };
    support.transformProp = support.transform.name.replace(/([A-Z])/g, '-$1').toLowerCase();
    return support;
}());

Je n'ai pas ajouté le code pour détecter les propriétés "d'animation" de chaque navigateur. J'ai fait cette réponse "wiki de la communauté" et je vous le laisse. :-)

92
David Murdoch

Vous devez d'abord supprimer l'animation, puis l'ajouter à nouveau. Par exemple:

document.getElementById("box").style.webkitAnimationName = "";
setTimeout(function ()
{
    document.getElementById("box").style.webkitAnimationName = "shake";
}, 0);

Pour ce faire sans setTimeout, supprimez l'animation pendant onmousedown et ajoutez-la pendant onclick:

someElem.onmousedown = function()
{
    document.getElementById("box").style.webkitAnimationName = "";
}
someElem.onclick = function()
{
    document.getElementById("box").style.webkitAnimationName = "shake";
}
13
gilly3

Une alternative simple mais efficace:

HTML:

<div id="box"></div>
<button id="shake-the-box">Shake it!</button>​

css:

#box{
    background: blue;
    margin:30px;
    height:50px;
    width:50px;
    position:relative;
    -moz-animation:shake .2s 0 linear 1; 
    -webkit-animation:shake .2s 0 linear 1; 
}
#box.trigger{
    display:table;
}
@-webkit-keyframes shake {
    0% {
        left: 0;
    }
    25% {
        left: 12px;
    }
    50% {
        left: 0;
    }
    75% {
        left: -12px;
    }
    100% {
        left:0;
    }
}
@-moz-keyframes shake {
    0% {
        left: 0;
    }
    25% {
        left: 12px;
    }
    50% {
        left: 0;
    }
    75% {
        left: -12px;
    }
    100% {
        left:0;
    }
}​

jQuery:

$('#shake-the-box').click(function(){

  $('#box').toggleClass('trigger');

});​

Démo:
http://jsfiddle.net/5832R/2/

Problèmes:
Je ne sais pas si cela fonctionne sur Firefox, car l'animation ne semble pas fonctionner là-bas ...

6
Puyol

Suite à la suggestion de https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Tips , supprimez puis ajoutez la classe d'animation, à l'aide de requestAnimationFrame pour vous assurer que le rendu Le moteur traite les deux modifications. Je pense que cela est plus propre que d'utiliser setTimeout et gère la lecture d'une animation avant la fin de la lecture précédente.

$('#shake-the-box').click(function(){   
  $('#box').removeClass("trigger");
  window.requestAnimationFrame(function(time) {
  window.requestAnimationFrame(function(time) {
      $('#box').addClass("trigger");
    });
    });    

});

http://jsfiddle.net/gcmwyr14/5/

6
Debby Mendez

Le clone fonctionne plutôt bien sur une pause Karaoké: sur IE11, il fallait forcer un refoulement (version plus courte de R. Krupiński).

$('#lyrics').text("Why does it hurt when I pee?");
changeLyrics('3s');  

function changeLyrics(sec) {
  str = 'lyrics '+ sec + ' linear 1';
  $('#lyrics').css( 'animation', str);
  $('#lyrics').css( 'animation-play-state', 'running' );
  $('#lyrics').replaceWith($('#lyrics').clone(true)); 
}

ou vous pouvez utiliser les éléments suivants:

function resetAnimation(Elm) {
  $('#'+Elm).replaceWith($('#'+Elm).clone(true)); 
}
1
user3026911

Existe-t-il un problème d'utilisation de setTimeout() pour supprimer la classe, puis la lire 5 ms plus tard?

svg.classList.remove('animate');
setTimeout(function() {
  svg.classList.add('animate');
}, 10);
1
Jeremy Lynch

Réinitialiser la valeur en premier. Utilisez le refusion pour appliquer la modification sans utiliser le délai d'expiration:

function shake() {
  var box = document.getElementById("box");
  box.style.animationName = null;
  box.offsetHeight; /* trigger reflow */
  box.style.animationName = "shake";
}
@keyframes shake {
    0% { left: 0; }
   25% { left: 12px; }
   50% { left: 0; }
   75% { left: -12px; }
  100% { left: 0; }
}

#box {
    position: absolute;
    width: 75px; height: 75px;
    background-color: black;
    animation-duration: .02s;
    animation-iteration-count: 10;
    animation-timing-function: linear;
}

button {
    position: absolute;
    top: 100px;
}
<div id="box"></div>
<button onclick="shake()">Shake</button>

Contrairement à la réponse acceptée qui recommande animationEnd, cette méthode réinitialise l'animation même si elle est encore en cours. Cela pourrait être ou ne pas être ce que vous voulez.


Une alternative serait de créer un duplicata @keyframes _ animation et bascule entre les deux:

function shake() {
  var box = document.getElementById("box");
  if (box.style.animationName === "shake")
      box.style.animationName = "shake2";
  else
      box.style.animationName = "shake";
}
@keyframes shake {
    0% { left: 0; }
   25% { left: 12px; }
   50% { left: 0; }
   75% { left: -12px; }
  100% { left: 0; }
}

@keyframes shake2 {
    0% { left: 0; }
   25% { left: 12px; }
   50% { left: 0; }
   75% { left: -12px; }
  100% { left: 0; }
}

#box {
    position: absolute;
    width: 75px; height: 75px;
    background-color: black;
    animation-duration: .02s;
    animation-iteration-count: 10;
    animation-timing-function: linear;
}

button {
    position: absolute;
    top: 100px;
}
<div id="box"></div>
<button onclick="shake()">Shake</button>
1
user

Avec votre javascript, vous pouvez également ajouter (puis supprimer) une classe CSS dans laquelle l’animation est déclarée. Tu vois ce que je veux dire ?

#cart p.anim {
  animation: demo 1s 1; // Fire once the "demo" animation which last 1s
}
0
Nico Prat

1) Ajoutez le nom de l'animation au #box.trigger en css

#box.trigger{
    display:table;
    animation:shake .2s 0 linear 1;
    -moz-animation:shake .2s 0 linear 1; 
    -webkit-animation:shake .2s 0 linear 1;
}

2) En Java-script, vous ne pouvez pas supprimer la classe trigger.

3) Supprimez le nom de la classe en utilisant la méthode setTimeOut.

$(document).ready(function(){
    $('#shake-the-box').click(function(){

    $('#box').addClass('trigger');
    setTimeout(function(){
        $("#box").removeClass("trigger")},500)        
    });
}); 

4) Voici le DÉMO .

0
Vamsi Velaga