Was ist der sauberste Weg, um CSS-Übergangseffekte vorübergehend zu deaktivieren?

209

Ich habe ein DOM-Element mit einigen / allen der folgenden angewendeten Effekte:

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

Ich schreibe ein jQuery-Plugin, dessen Größe sich ändert. Ich muss diese Effekte vorübergehend deaktivieren, damit ich die Größe problemlos ändern kann.

Was ist die eleganteste Methode, um diese Effekte vorübergehend zu deaktivieren (und dann wieder zu aktivieren), da sie möglicherweise von den Eltern angewendet werden oder überhaupt nicht angewendet werden.

Sam Safran
quelle
1
Das sieht vielversprechend aus: ricostacruz.com/jquery.transit . Es ist MIT-lizenziert, Sie können es also entweder einbauen oder studieren, um zu sehen, wie er es macht.
Robert Harvey
Alle Antworten fügen eine .notransitionKlasse hinzu. Es wäre vernünftiger, es umgekehrt zu machen, dh #elem.yestransitionmit Ihrem CSS zu zielen und diese Klasse zu entfernen. Das beseitigt böse *s in Ihrem CSS.
marcellothearcane

Antworten:

484

Kurze Antwort

Verwenden Sie dieses CSS:

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

Plus entweder diese JS (ohne 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

Oder dieses JS mit jQuery ...

$someElement.addClass('notransition'); // Disable transitions
doWhateverCssChangesYouWant($someElement);
$someElement[0].offsetHeight; // Trigger a reflow, flushing the CSS changes
$someElement.removeClass('notransition'); // Re-enable transitions

... oder gleichwertiger Code mit einer anderen Bibliothek oder einem anderen Framework, mit dem Sie arbeiten.

Erläuterung

Dies ist eigentlich ein ziemlich subtiles Problem.

Zunächst möchten Sie wahrscheinlich eine 'notransition'-Klasse erstellen, die Sie auf Elemente anwenden können, um deren *-transitionCSS-Attribute festzulegen none. Zum Beispiel:

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

(Nebenbei bemerkt - beachten Sie das Fehlen eines -ms-transitionIn. Sie benötigen es nicht. Die erste Version von Internet Explorer, die Übergänge überhaupt unterstützt, war IE 10, die sie ohne Fix unterstützt.)

Aber das ist nur Stil und das ist das Einfache. Wenn Sie versuchen, diese Klasse zu verwenden, stoßen Sie auf eine Falle. Die Falle ist, dass Code wie dieser nicht so funktioniert, wie Sie es naiv erwarten könnten:

// 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')

Naiv könnte man denken, dass die Änderung der Höhe nicht animiert wird, da dies geschieht, während die Klasse 'notransition' angewendet wird. In Wirklichkeit aber ist es werden animiert werden, zumindest in allen modernen Browsern habe ich versucht. Das Problem ist, dass der Browser die Stiländerungen zwischenspeichert, die er vornehmen muss, bis das JavaScript vollständig ausgeführt wird, und dann alle Änderungen in einem einzigen Reflow vornimmt. Infolgedessen wird ein Reflow durchgeführt, bei dem sich nicht netto ändert, ob Übergänge aktiviert sind oder nicht, sondern die Höhe netto geändert wird. Folglich wird die Höhenänderung animiert.

Sie könnten denken, ein vernünftiger und sauberer Weg, um dies zu umgehen, wäre, das Entfernen der 'notransition'-Klasse in eine Zeitüberschreitung von 1 ms wie folgt einzuschließen:

// 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);

aber das funktioniert auch nicht zuverlässig. Ich konnte den obigen Code in WebKit-Browsern nicht brechen, aber auf Firefox (sowohl auf langsamen als auch auf schnellen Computern) wird manchmal (scheinbar zufällig) das gleiche Verhalten wie bei der Verwendung des naiven Ansatzes angezeigt. Ich denke, der Grund dafür ist, dass die JavaScript-Ausführung möglicherweise so langsam ist, dass die Timeout-Funktion auf die Ausführung wartet, wenn der Browser inaktiv ist, und ansonsten über einen opportunistischen Reflow nachdenken würde. Wenn dieses Szenario eintritt, Firefox führt die Funktion in der Warteschlange vor dem Reflow aus.

Die einzige Lösung, die ich für das Problem gefunden habe, besteht darin , einen Reflow des Elements zu erzwingen und die daran vorgenommenen CSS-Änderungen zu löschen, bevor die Klasse 'notransition' entfernt wird. Es gibt verschiedene Möglichkeiten, dies zu tun - siehe hier für einige. Das, was einer Standardmethode am nächsten kommt, ist das Lesen der offsetHeightEigenschaft des Elements.

Eine Lösung, die tatsächlich funktioniert, ist

someElement.classList.add('notransition'); // Disable transitions
doWhateverCssChangesYouWant(someElement);
someElement.offsetHeight; // Trigger a reflow, flushing the CSS changes
someElement.classList.remove('notransition'); // Re-enable transitions

Hier ist eine JS-Geige, die die drei möglichen Ansätze veranschaulicht, die ich hier beschrieben habe (sowohl den einen erfolgreichen als auch die beiden erfolglosen): http://jsfiddle.net/2uVAA/131/

Mark Amery
quelle
8
Excelente Antwort. Gute Arbeit und geschätzt, da ich das gleiche Problem hatte. Was wäre, wenn ich nur eine Art von Übergang entfernen wollte?
Rafaelmorais
2
Ihre Lösung ist richtig, aber für diejenigen, die mehr Hintergrundinformationen suchen: stackoverflow.com/a/31862081/1026
Nickolay
2
Abgesehen von Minor Minor war IE10 die erste stabile Version von IE, die mit nicht festgelegten Übergängen ausgeliefert wurde. Die Vorabversionen, mit Ausnahme der Versionsvorschau, erforderten das Präfix -ms- für Übergänge sowie eine Reihe anderer Dinge. Ich vermute, dass dies einer der Gründe ist, warum das Präfix -ms- heute erscheint. Der andere, viel wahrscheinlichere Grund ist der übliche Frachtkult, den wir alle über Herstellerpräfixe kennen und lieben gelernt haben.
BoltClock
1
Interessant, dass das einfache Überprüfen der Versatzhöhe eines Elements einen Reflow auslöst. Ich wünschte, ich wüsste das vor einem Jahr, als ich meinen Kopf mit demselben Problem gegen die Wand schlug. Wird dies immer noch als die idealste Methode angesehen, um damit umzugehen?
Brett84c
2
Der Reflow-Trick scheint nicht zu funktionieren, wenn SVG-Elemente animiert werden, die kein offsetHeight-Attribut haben. setTimout funktioniert.
piotr_cz
19

Fügen Sie eine zusätzliche CSS-Klasse hinzu, die den Übergang blockiert, und entfernen Sie sie, um zum vorherigen Status zurückzukehren. Dies macht sowohl CSS- als auch JQuery-Code kurz, einfach und verständlich.

CSS :

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

!important wurde hinzugefügt, um sicherzustellen, dass diese Regel mehr "Gewicht" hat, da ID normalerweise spezifischer als Klasse ist.

JQuery :

$('#elem').addClass('notransition'); // to remove transition
$('#elem').removeClass('notransition'); // to return to previouse transition
DaneSoul
quelle
5
-1, da dies nicht ausreichte, um das Problem in Chrome oder Firefox für mich zu lösen. Wenn ich über Javascript verfüge, das die Klasse hinzufügt, die Änderungen vornimmt und die Klasse entfernt, werden die Änderungen manchmal noch animiert. Ich habe die letzten ein oder zwei Stunden damit verbracht, dieses Problem genauer zu untersuchen, und werde später eine Antwort mit Geigen veröffentlichen, die Fälle zeigen, in denen der naive Ansatz fehlschlägt, sowie einen ordentlichen Hack, der die Lösung hier behebt, indem er einen Reflow zwischen dem Vornehmen der Änderungen und dem Entfernen erzwingt die 'notransition'-Klasse.
Mark Amery
18

Ich würde empfehlen, die Animation zu deaktivieren, wie von DaneSoul vorgeschlagen, aber den Wechsel global zu gestalten:

/*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; 
} 

.notransitionkann dann auf das bodyElement angewendet werden , wodurch alle Übergangsanimationen auf der Seite effektiv überschrieben werden:

$('body').toggleClass('notransition');
ov
quelle
2
Eigentlich ist dies die perfekte Option imo. Besonders das * hilft sehr, um sicherzustellen, dass keine der Unteranimationen ausgelöst wird. Danke, positiv bewertet.
SchizoDuckie
Dies ist die richtige Antwort für Situationen, in denen Sie nur alles auf einmal tun möchten. Zum Beispiel möchte ich Übergänge deaktivieren, während ich mich auf dem Handy drehe, und das ist perfekt dafür.
Ben Lachman
Ich habe dies in Angularjs verwendet, in einem etwas komplizierten Szenario, aber bei Gott war dies nach Tagen, in denen ich mir den Kopf schlug, so hilfreich.
Aditya MP
2
In Bezug auf die Leistung kann ich nicht erwarten, dass dies überhaupt eine gute Idee ist. "Oh, wende das einfach auf ALLES auf der Seite an, das macht die Sache einfacher!"
Lodewijk
1
Sollte wahrscheinlich sowohl ".notransition" als auch ".notransition *" auswählen, um voll wirksam zu sein.
Nathan
9

Für eine reine JS-Lösung (keine CSS-Klassen) setzen Sie einfach transitionauf 'none'. Um den im CSS angegebenen Übergang wiederherzustellen, setzen Sie den transitionauf eine leere Zeichenfolge.

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

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

Wenn Sie Herstellerpräfixe verwenden, müssen Sie diese ebenfalls festlegen.

elem.style.webkitTransition = 'none'
Thomas Higginbotham
quelle
8

Mit diesem CSS-Code können Sie Animationen, Übergänge und Transformationen für alle Elemente auf der Seite deaktivieren

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);
Ali
quelle
1
Erstens ist das großartig, danke! Zweitens gibt es auch einige andere Eigenschaften, die festgelegt werden sollten; siehe github.com/japgolly/test-state/blob/master/util/shared/src/test/…
Golly
@ Golly Diese anderen Eigenschaften könnten das endgültige Design beeinflussen
Jonperl
0

Ich denke, Sie könnten eine separate CSS-Klasse erstellen, die Sie in folgenden Fällen verwenden können:

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

Dann würden Sie in jQuery die Klasse wie folgt umschalten:

$('#<your-element>').addClass('disable-transition');
Cyclonecode
quelle
Ja, ich denke, dies ist der beste Ansatz. Tatsächlich kann das Plugin diesen CSS-Block in die Seite einfügen
Sam Saffron
3
Sind Sie sicher, dass ohne! Wichtiges CLASS-Lineal ID 1 überschreibt?
DaneSoul
0

Wenn Sie eine einfache No-JQuery-Lösung wünschen, um alle Übergänge zu verhindern:

  1. Fügen Sie dieses CSS hinzu:
body.no-transition * {
  transition: none !important;
}
  1. Und dann in deinem js:
document.body.classList.add("no-transition");

// do your work, and then either immediately remove the class:

document.body.classList.remove("no-transition");

// or, if browser rendering takes longer and you need to wait until a paint or two:

setTimeout(() => document.body.classList.remove("no-transition"), 1);

// (try changing 1 to a larger value if the transition is still applying)
mrm
quelle
-1

Wenn Sie CSS-Übergänge, -Transformationen und -Animationen von der aktuellen Webseite entfernen möchten, können Sie einfach dieses kleine Skript ausführen, das ich geschrieben habe (in der Browserkonsole):

let filePath = "https://dl.dropboxusercontent.com/s/ep1nzckmvgjq7jr/remove_transitions_from_page.css";
let html = `<link rel="stylesheet" type="text/css" href="${filePath}">`;
document.querySelector("html > head").insertAdjacentHTML("beforeend", html);

Es verwendet vanillaJS, um diese CSS-Datei zu laden . Hier ist auch ein Github-Repo, falls Sie dies im Zusammenhang mit einem Scraper (Ruby-Selenium) verwenden möchten: remove-CSS-animations-repo

Thomas
quelle
-3

tut

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

in deinem js es töten?

offensichtlich für jeden wiederholen.

Chris
quelle
1
dann müssen Sie es nachträglich zurücksetzen, also müssen Sie es speichern, was zu einer angemessenen Menge
Sam Saffron
-4

Ich hätte eine Klasse in Ihrem CSS wie folgt:

.no-transition { 
  -webkit-transition: none;
  -moz-transition: none;
  -o-transition: none;
  -ms-transition: none;
  transition: none;
}

und dann in Ihrer jQuery:

$('#elem').addClass('no-transition'); //will disable it
$('#elem').removeClass('no-transition'); //will enable it
Moin Zaman
quelle
1
Sind Sie sicher, dass ohne! Wichtiges CLASS-Lineal ID 1 überschreibt?
DaneSoul
1
Ja, das wird es, weil Sie jetzt auf # elem.no-Transition abzielen, das spezifischer ist als nur die ID
Moin Zaman
3
@MoinZaman Ähm, aber Sie haben#elem.no-transition in Ihrem CSS nicht gezielt , sondern nur gezielt .no-transition. Vielleicht wollten Sie #elem.no-transitionin Ihr CSS schreiben ?
Mark Amery