Каков самый чистый способ временно отключить эффекты перехода CSS?

У меня есть элемент DOM с некоторыми/всеми следующими эффектами:

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

Я пишу плагин jQuery, который изменяет размер этого элемента, мне нужно временно отключить эти эффекты, чтобы я мог изменять его плавно.

Каков самый элегантный способ временно отключить эти эффекты (а затем снова включить их), поскольку они могут применяться от родителей или вообще не могут применяться.

Ответ 1

Короткий ответ

Используйте этот CSS:

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

Плюс либо этот JS (без 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

Или этот JS с JQuery...

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

... или эквивалентный код с использованием любой другой библиотеки или фреймворка, с которым вы работаете.

объяснение

Это на самом деле довольно тонкая проблема.

Во-первых, вы, вероятно, захотите создать класс "notransition", который вы можете применить к элементам, чтобы установить для их *-transition CSS *-transition значение none. Например:

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

(Незначительно, обратите внимание на отсутствие -ms-transition там. Вам это не нужно. Первой версией Internet Explorer для поддержки переходов вообще был IE 10, который поддерживал их без префикса.)

Но это просто стиль, и это легко. Когда вы попытаетесь использовать этот класс, вы попадете в ловушку. Ловушка в том, что такой код не будет работать так, как вы могли бы наивно ожидать:

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

Наивно, вы можете подумать, что изменение высоты не будет анимированным, потому что это происходит, когда применяется класс notransition. На самом деле, он будет анимированным, по крайней мере, во всех современных браузерах, которые я пробовал. Проблема заключается в том, что браузер кэширует изменения стиля, которые он должен внести до завершения выполнения JavaScript, а затем вносит все изменения в одном перекомпоновании. В результате он выполняет перекомпоновку, где нет чистого изменения того, включены ли переходы, но есть чистое изменение высоты. Следовательно, это оживляет изменение высоты.

Вы могли бы подумать, что разумным и чистым способом обойти это было бы завершение удаления класса "notransition" за 1 мс, например:

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

но это тоже не работает надежно. Я не смог сделать описанный выше разрыв кода в браузерах WebKit, но в Firefox (как на медленных, так и на быстрых машинах) вы иногда (на первый взгляд, наугад) получаете то же поведение, что и при использовании наивного подхода. Я предполагаю, что причина этого заключается в том, что выполнение JavaScript может быть достаточно медленным, чтобы функция тайм-аута ожидала выполнения к тому времени, когда браузер бездействует, и в противном случае могла бы подумать о выполнении оппортунистического перекомпоновки, и если этот сценарий произойдет, Firefox выполняет функцию из очереди до перекомпоновки.

Единственное решение, которое я нашел для этой проблемы, состоит в том, чтобы принудительно перекомпоновать элемент, сбрасывая изменения CSS, внесенные в него, перед удалением класса notransition. Существуют различные способы сделать это - посмотрите здесь для некоторых. Наиболее близким к этому стандартному способу является чтение свойства offsetHeight элемента.

Одно из решений, которое действительно работает,

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

Вот скрипка JS, которая иллюстрирует три возможных подхода, которые я описал здесь (как один успешный, так и два неудачных): http://jsfiddle.net/2uVAA/131/

Ответ 2

Добавьте дополнительный класс CSS, который блокирует переход, а затем удалите его, чтобы вернуться в предыдущее состояние. Это делает код CSS и JQuery коротким, простым и понятным.

CSS

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

!important был добавлен, чтобы быть уверенным, что это правило будет иметь больше "веса", поскольку идентификатор обычно более специфичен, чем класс.

JQuery

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

Ответ 3

Я бы рекомендовал отключить анимацию, предложенную DaneSoul, но сделав глобальный переключатель:

/*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 может быть применен к элементу body, эффективно перекрывая любую переходную анимацию на странице:

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

Ответ 4

Для чистого решения JS (без классов CSS) просто установите transition в 'none'. Чтобы восстановить переход, как указано в CSS, установите transition в пустую строку.

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

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

Если вы используете префиксы поставщиков, вам также необходимо установить их.

elem.style.webkitTransition = 'none'

Ответ 5

Вы можете отключить анимацию, переход, trasforms для всего элемента на странице с помощью этого кода 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

Я думаю, вы могли бы создать отдельный класс css, который вы можете использовать в этих случаях:

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

Затем в jQuery вы должны переключить класс следующим образом:

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

Ответ 7

делает

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

в js убить его?

очевидно, повторяются для каждого.

Ответ 8

У меня будет класс в CSS следующим образом:

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

а затем в вашем jQuery:

$('#elem').addClass('no-transition'); //will disable it
$('#elem').removeClass('no-transition'); //will enable it