231 votes

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

J'ai un élément DOM avec certains/toutes 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. J'ai besoin de désactiver temporairement ces effets pour pouvoir le redimensionner en douceur.

Quelle est la manière la plus élégante de désactiver temporairement ces effets (puis de les réactiver), étant donné qu'ils peuvent être appliqués à partir des parents ou ne pas être appliqués du tout.

1 votes

Cela semble prometteur : ricostacruz.com/jquery.transit . Il est sous licence MIT, vous pouvez donc soit l'intégrer, soit l'étudier pour voir comment il s'y prend.

0 votes

Toutes les réponses ajouter a .notransition classe. Il serait plus raisonnable de le faire dans l'autre sens, c'est-à-dire de cibler #elem.yestransition avec votre css et supprimez cette classe. Cela permet de ne plus avoir de * dans votre css.

529voto

Mark Amery Points 4705

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 utilisant une autre bibliothèque ou un autre framework avec lequel vous travaillez.

Explication

Il s'agit en fait d'un problème assez subtil.

Tout d'abord, vous souhaitez probablement créer une classe "notransition" que vous pouvez appliquer aux éléments pour définir leur *-transition Attributs CSS pour none . Par exemple :

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

<i>(Petite parenthèse - notez l'absence d'un <code>-ms-transition</code> là-dedans. Vous n'en avez pas besoin. La première version d'Internet Explorer à prendre en charge les transitions <em>du tout </em>était IE 10, qui les supportait sans fixation).</i>

Mais ce n'est que du style, et c'est le plus facile. Lorsque vous essayerez d'utiliser cette classe, vous vous heurterez à un piège. Le piège est que le code comme celui-ci ne fonctionnera pas de la façon dont vous pourriez naïvement vous y attendre :

// 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 être 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 effectuer jusqu'à ce que le JavaScript ait fini de s'exécuter, puis effectue toutes les modifications en une seule fois. En conséquence, il effectue une refonte où il n'y a pas de changement net de l'activation ou non des transitions, mais où il y a un changement net 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 d'envelopper la suppression de la classe 'notransition' dans un délai d'attente de 1ms, 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 non plus de manière fiable. Je n'ai pas réussi à faire en sorte que le code ci-dessus ne fonctionne pas dans les navigateurs WebKit, mais sur Firefox (sur des 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 du 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 qu'il penserait autrement à effectuer un reflux opportuniste, et si ce scénario se produit, Firefox exécute la fonction en attente avant le reflux.

La seule solution que j'ai trouvée à ce problème est de force une refonte de l'élément, en vidant les modifications CSS qui lui ont été apportées, avant de supprimer la classe "notransition". Il existe plusieurs façons de procéder - voir aquí pour certains. La méthode la plus proche d'une méthode "standard" consiste à lire le manuel de l'utilisateur. 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 bidule JS qui illustre les trois approches possibles que j'ai décrites ici (à la fois l'approche réussie et les deux autres qui ont échoué) : http://jsfiddle.net/2uVAA/131/

8 votes

Excelente réponse. Bon travail, et apprécié puisque j'ai rencontré le même problème. Et si je ne voulais supprimer qu'un seul type de transition ?

2 votes

Votre solution est bonne, mais pour ceux qui cherchent plus d'informations de fond : stackoverflow.com/a/31862081/1026

2 votes

Mineur mineur mis à part, IE10 a été le premier stable d'IE avec des transitions non corrigées. Les versions antérieures, à l'exception de la Release Preview, exigeaient le préfixe -ms- pour les transitions, ainsi qu'un grand nombre d'autres éléments. Je pense que c'est l'une des raisons pour lesquelles le préfixe -ms- apparaît aujourd'hui. L'autre raison, bien plus probable bien sûr, est l'habituel culte du cargo que nous avons tous appris à connaître et à aimer à propos des préfixes des fournisseurs.

21voto

DaneSoul Points 1969

Ajoutez une classe CSS supplémentaire qui bloque la transition, puis supprimez-la pour revenir à l'état précédent. Cela rend le code CSS et JQuery court, simple et bien compréhensible.

CSS :

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

Note : !important a été ajouté pour être sûr que cette règle aura une préférence plus élevée, car l'utilisation d'un id est plus spécifique que la classe.

JQuery :

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

5 votes

-1 parce que cela n'a pas suffi à résoudre le problème pour moi dans Chrome ou Firefox - si j'ai du Javascript qui ajoute la classe, fait les changements, et enlève la classe, parfois les changements toujours animer. J'ai passé la dernière heure ou deux à étudier ce problème en détail et je posterai une réponse plus tard avec des bidouillages montrant les cas où l'approche naïve échoue, plus une astuce qui corrige la solution ici en forçant un reflux entre les changements et la suppression de la classe 'notransition'.

0 votes

Je recommande de ne pas utiliser !important à moins d'y être obligé. Cela peut causer BEAUCOUP de maux de tête par la suite. J'ai essayé de le faire sans et tant que vous suivez les règles de cascade CSS, cela fonctionne bien.

20voto

o.v. Points 11173

Je préconise de désactiver l'animation comme le suggère DaneSoul, mais de rendre le changement 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 alors être appliquée à la body ce qui a pour effet de remplacer toute animation de transition sur la page :

$('body').toggleClass('notransition');

2 votes

En fait, c'est l'option parfaite, imo. En particulier, l'astérisque * aide beaucoup, en s'assurant qu'aucune des animations secondaires n'est déclenchée. Merci, upvoted.

0 votes

C'est la bonne réponse pour les situations où vous voulez tout faire en même temps. Par exemple, je veux désactiver les transitions lors de la rotation sur mobile et c'est parfait pour cela.

0 votes

J'ai fini par l'utiliser dans angularjs, dans un scénario un peu compliqué, mais bon sang, c'était tellement utile après des jours à me taper la tête.

2voto

Krister Andersson Points 9788

Je pense que vous pourriez créer une classe css distincte que vous pourriez utiliser dans ces cas :

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

Ensuite, dans jQuery, vous basculez la classe comme suit :

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

0 votes

Oui je pense que c'est la meilleure approche, en fait le plugin peut injecter ce bloc css dans la page

3 votes

Etes-vous sûr que sans !important CLASS ruler remplacera ID one ?

-2voto

Chris Points 455

Fait

$('#elem').css('-webkit-transition','none !important'); 

dans vos js le tuer ?

évidemment répéter pour chacun.

1 votes

Alors vous devez le réinitialiser après coup, donc vous devez le stocker, ce qui conduirait à une quantité considérable d'instructions générales.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X