web-dev-qa-db-fra.com

Quel est le moyen le plus propre de désactiver temporairement les effets de transition CSS?

J'ai un élément DOM avec certains/tous les effets suivants appliqués:

#elem {
  -webkit-transition: height 0.4s ease;
  -moz-transition: height 0.4s ease;
  -o-transition: height 0.4s ease;
  transition: height 0.4s ease;
}

J'écris un plugin jQuery qui redimensionne cet élément, je dois désactiver ces effets temporairement pour pouvoir le redimensionner facilement.

Quel est le moyen le plus élégant de désactiver temporairement ces effets (puis de les réactiver), étant donné qu'ils peuvent être appliqués par les parents ou peuvent ne pas être appliqués du tout.

187
Sam Saffron

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 un code équivalent en utilisant la bibliothèque ou le framework avec lequel vous travaillez.

Explication

C'est en fait un problème assez subtil.

Tout d'abord, vous voulez probablement créer une classe 'notransition' que vous pouvez appliquer aux éléments pour définir leurs attributs *-transition CSS sur none. Par exemple:

.notransition {
  -webkit-transition: none !important;
  -moz-transition: none !important;
  -o-transition: none !important;
  transition: none !important;
}

(Mineure à part - notez l'absence de -ms-transition dans celui-ci. Vous n'en avez pas besoin. La première version d'Internet Explorer pour supporter les transitions du tout était IE 10, qui les a pris en charge sans préfixe.)

Mais ce n'est que style, et c'est la partie facile. Lorsque vous tenterez d’utiliser cette classe, vous rencontrerez un piège. Le piège est que le code comme celui-ci ne fonctionnera pas comme on pourrait s'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é, 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 nécessaires jusqu'à la fin de l'exécution de JavaScript, puis effectue toutes les modifications en une seule redistribution. En conséquence, il effectue une redistribution sans modification nette indiquant si les transitions sont activées ou non, mais une modification nette de la hauteur. Par conséquent, il anime le changement de hauteur.

Vous pourriez penser qu'une façon raisonnable et propre de contourner ce problème serait de terminer le retrait de la classe 'notransition' par 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 été en mesure de supprimer le code ci-dessus dans les navigateurs WebKit, mais sur Firefox (sur les machines lentes et rapides), vous aurez parfois (apparemment au hasard) le même comportement que si vous utilisiez 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 serait sinon en train de penser à une redistribution opportuniste, et si ce scénario se produit, Firefox exécute la fonction en file d'attente avant le redistribution.

La seule solution que j'ai trouvée au problème consiste à forcer le refoulement de l'élément, en effaçant les modifications CSS apportées, avant de supprimer la classe 'notransition'. Il y a différentes façons de le faire - voir ici pour certains. Pour ce faire, la méthode la plus proche consiste à lire la propriété offsetHeight de l'élément.

Une solution qui fonctionne réellement, 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 (l'approche réussie et les deux non réussies): http://jsfiddle.net/2uVAA/131/

444
Mark Amery

Ajoutez une classe CSS supplémentaire qui bloque la transition, puis supprimez-la pour revenir à l'état précédent. Cela rend les codes CSS et JQuery courts, simples et bien compréhensibles.

CSS:

.notransition {
  -webkit-transition: none !important;
  -moz-transition: none !important;
  -o-transition: none !important;
  -ms-transition: none !important;
  transition: none !important;
}

!important a été ajouté pour être sûr que cette règle aura plus de "poids", car l'ID est normalement plus spécifique que la classe.

JQuery:

$('#elem').addClass('notransition'); // to remove transition
$('#elem').removeClass('notransition'); // to return to previouse transition
17
DaneSoul

Je recommanderais de désactiver l’animation comme suggéré par DaneSoul, mais en rendant le commutateur global:

/*kill the transitions on any descendant elements of .notransition*/
.notransition * { 
  -webkit-transition: none !important; 
  -moz-transition: none !important; 
  -o-transition: none !important; 
  -ms-transition: none !important; 
  transition: none !important; 
} 

.notransition peut ensuite être appliqué à l'élément body, annulant ainsi toute animation de transition sur la page:

$('body').toggleClass('notransition');
15
o.v.

Pour une solution JS pure (pas de classes CSS), définissez simplement transition sur 'none'. Pour restaurer la transition comme spécifié dans le CSS, définissez la variable transition sur une chaîne vide.

// Remove the transition
elem.style.transition = 'none';

// Restore the transition
elem.style.transition = '';

Si vous utilisez des préfixes de fournisseur, vous devrez également les définir.

elem.style.webkitTransition = 'none'
8

Vous pouvez désactiver l'animation, la transition, les transformations pour tous les éléments de la page avec ce code CSS

var style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = '* {' +
'/*CSS transitions*/' +
' -o-transition-property: none !important;' +
' -moz-transition-property: none !important;' +
' -ms-transition-property: none !important;' +
' -webkit-transition-property: none !important;' +
'  transition-property: none !important;' +
'/*CSS transforms*/' +
'  -o-transform: none !important;' +
' -moz-transform: none !important;' +
'   -ms-transform: none !important;' +
'  -webkit-transform: none !important;' +
'   transform: none !important;' +
'  /*CSS animations*/' +
'   -webkit-animation: none !important;' +
'   -moz-animation: none !important;' +
'   -o-animation: none !important;' +
'   -ms-animation: none !important;' +
'   animation: none !important;}';
   document.getElementsByTagName('head')[0].appendChild(style);
6
Ali

Je pense que vous pouvez créer une classe CSS distincte que vous pouvez utiliser dans les cas suivants:

.disable-transition {
  -webkit-transition: none;
  -moz-transition: none;
  -o-transition: color 0 ease-in;
  -ms-transition: none;
  transition: none;
}

Ensuite, dans jQuery, vous pouvez basculer la classe de la manière suivante:

$('#<your-element>').addClass('disable-transition');
0
Cyclonecode