Réponse courte
Utilisez ce CSS:
.notransition {
-webkit-transition: none !important;
-moz-transition: none !important;
-o-transition: none !important;
transition: none !important;
}
Plus soit ce JS (sans jQuery) ...
someElement.classList.add('notransition'); // Disable transitions
doWhateverCssChangesYouWant(someElement);
someElement.offsetHeight; // Trigger a reflow, flushing the CSS changes
someElement.classList.remove('notransition'); // Re-enable transitions
Ou ce JS avec jQuery ...
$someElement.addClass('notransition'); // Disable transitions
doWhateverCssChangesYouWant($someElement);
$someElement[0].offsetHeight; // Trigger a reflow, flushing the CSS changes
$someElement.removeClass('notransition'); // Re-enable transitions
... ou du code équivalent utilisant n'importe quelle autre bibliothèque ou framework avec lequel vous travaillez.
Explication
Il s'agit en fait d'un problème assez subtil.
Tout d'abord, vous souhaiterez probablement créer une classe «notransition» que vous pouvez appliquer aux éléments pour définir leurs *-transition
attributs CSS none
. Par exemple:
.notransition {
-webkit-transition: none !important;
-moz-transition: none !important;
-o-transition: none !important;
transition: none !important;
}
(Mineure de côté - notez l'absence d'un -ms-transition
. Vous n'en avez pas besoin. La première version d'Internet Explorer pour prendre en charge les transitions du tout était IE 10, qui les supportait préfixés.)
Mais ce n'est que du style et c'est la partie la plus facile. Lorsque vous venez d'essayer et d'utiliser cette classe, vous rencontrerez un piège. Le piège est que le code comme celui-ci ne fonctionnera pas comme vous pourriez vous y attendre naïvement:
// Don't do things this way! It doesn't work!
someElement.classList.add('notransition')
someElement.style.height = '50px' // just an example; could be any CSS change
someElement.classList.remove('notransition')
Naïvement, vous pourriez penser que le changement de hauteur ne sera pas animé, car il se produit lorsque la classe «notransition» est appliquée. En réalité, cependant, il sera animé, du moins dans tous les navigateurs modernes que j'ai essayés. Le problème est que le navigateur met en cache les modifications de style qu'il doit apporter jusqu'à ce que JavaScript soit terminé, puis effectue toutes les modifications en une seule redistribution. Par conséquent, il effectue une refusion où il n'y a pas de changement net quant à l'activation ou non des transitions, mais il y a un changement net de la hauteur. Par conséquent, il anime le changement de hauteur.
Vous pourriez penser qu'un moyen raisonnable et propre de contourner ce problème serait d'encapsuler la suppression de la classe «notransition» dans un délai de 1 ms, comme ceci:
// Don't do things this way! It STILL doesn't work!
someElement.classList.add('notransition')
someElement.style.height = '50px' // just an example; could be any CSS change
setTimeout(function () {someElement.classList.remove('notransition')}, 1);
mais cela ne fonctionne pas de manière fiable non plus. Je n'ai pas pu faire la rupture de code ci-dessus dans les navigateurs WebKit, mais sur Firefox (sur les machines lentes et rapides), vous obtiendrez parfois (apparemment au hasard) le même comportement qu'en utilisant l'approche naïve. Je suppose que la raison en est qu'il est possible que l'exécution de JavaScript soit suffisamment lente pour que la fonction de délai d'attente soit en attente d'exécution au moment où le navigateur est inactif et penserait autrement à faire une redistribution opportuniste, et si ce scénario se produit, Firefox exécute la fonction en file d'attente avant la redistribution.
La seule solution que j'ai trouvée au problème est de forcer une redistribution de l'élément, en vidant les modifications CSS qui y sont apportées, avant de supprimer la classe 'notransition'. Il existe différentes façons de le faire - voir ici pour certains. La chose la plus proche d'une méthode «standard» est de lire leoffsetHeight
propriété de l'élément.
Une solution qui fonctionne alors est
someElement.classList.add('notransition'); // Disable transitions
doWhateverCssChangesYouWant(someElement);
someElement.offsetHeight; // Trigger a reflow, flushing the CSS changes
someElement.classList.remove('notransition'); // Re-enable transitions
Voici un violon JS qui illustre les trois approches possibles que j'ai décrites ici (à la fois l'approche réussie et les deux infructueuses):
http://jsfiddle.net/2uVAA/131/