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


210

У меня есть элемент 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
Это выглядит многообещающе: ricostacruz.com/jquery.transit . Это лицензия MIT, так что вы можете включить ее или изучить, как он это делает.
Роберт Харви

Все ответы добавить в .notransitionкласс. Было бы разумнее сделать это наоборот, то есть нацелиться #elem.yestransitionна css и удалить этот класс. Это устраняет наличие неприятных *s в вашем css.
марта

Ответы:


484

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

Используйте этот 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 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/


8
Превосходный ответ. Хорошая работа, и ценится, так как я придумал ту же проблему. Что если я хочу удалить только один тип перехода?
rafaelmorais

2
Ваше решение правильное, но для тех, кто ищет дополнительную справочную информацию: stackoverflow.com/a/31862081/1026
Николай

2
Незначительно незначительное в стороне, IE10 была первой стабильной версией IE, которая поставлялась с нефиксированными переходами. В предварительных версиях, за исключением Release Preview, требовался префикс -ms- для переходов, а также множество других вещей. Я подозреваю, что это одна из причин появления префикса -ms- сегодня. Другой, гораздо более вероятной причиной, конечно же, является обычный культ груза, который мы все знаем и любим в отношении префиксов поставщиков.
BoltClock

1
Интересно, что простая проверка высоты смещения элемента запускает перекомпоновку. Жаль, что я знал это год назад, когда я бился головой об стену с этой же проблемой. Это все еще считается самым идеальным способом справиться с этим?
Brett84c

2
Трюк с перекомпоновкой не работает при анимации SVG-элементов, которые не имеют атрибута offsetHeight; setTimout работает.
piotr_cz

19

Я бы выступил за отключение анимации в соответствии с предложением 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');

2
На самом деле это идеальный вариант ИМО. Особенно * очень помогает, убедившись, что ни одна из вспомогательных анимаций не запущена. Спасибо, проголосовал.
SchizoDuckie

Это правильный ответ для ситуаций, когда вы просто хотите сделать все сразу. Например, я хочу отключить переходы во время вращения на мобильном телефоне, и это идеально подходит для этого.
Бен Лахман

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

2
В плане производительности я не могу ожидать, что это будет хорошей идеей. «О, просто примените это ко ВСЕМУ на странице, это делает вещи проще!»
Lodewijk

1
Вероятно, следует выбрать «.notransition» и «.notransition *» для полной эффективности.
Натан

19

Добавьте дополнительный класс 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

5
-1, потому что этого было недостаточно, чтобы решить эту проблему для меня в Chrome или Firefox - если у меня есть Javascript, который добавляет класс, вносит изменения и удаляет класс, иногда изменения по- прежнему анимируются. Я провел последние час или два, изучая эту проблему более подробно, и позже опубликую ответ с скриптами, показывающими случаи, когда наивный подход терпит неудачу, плюс аккуратный хак, который исправляет решение здесь, заставляя перекомпоновку между внесением изменений и удалением класс «notransition».
Марк Эмери

9

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

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

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

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

elem.style.webkitTransition = 'none'

8

Вы можете отключить анимацию, переход, 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);

1
Во-первых, это здорово, спасибо! Во-вторых, есть также некоторые другие свойства, которые должны быть установлены; см. github.com/japgolly/test-state/blob/master/util/shared/src/test/…
Golly

@Golly Эти другие свойства могут повлиять на окончательный дизайн
jonperl

0

Я думаю, что вы могли бы создать отдельный класс 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');

да, я думаю, что это лучший подход, на самом деле плагин может добавить этот блок CSS на страницу
Сэм Саффрон

3
Вы уверены, что без! Важной линейки CLASS переопределит ID один?
DaneSoul

0

Если вам нужно простое решение без jquery для предотвращения всех переходов:

  1. Добавьте этот CSS:
body.no-transition * {
  transition: none !important;
}
  1. И тогда в вашем 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)

-1

Если вы хотите удалить CSS-переходы, преобразования и анимации с текущей веб-страницы, вы можете просто выполнить этот небольшой скрипт, который я написал (в консоли браузера):

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

Он использует vanillaJS для загрузки этого css-файла . Здесь также есть репозиторий github на случай, если вы захотите использовать его в контексте скребка (Ruby-Selenium): remove-CSS-animations-repo


-3

делает

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

в твоих js это убить?

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


1
затем вам нужно сбросить его после факта, поэтому вам нужно хранить его, что приведет к достаточному количеству котельной плиты
Сэм Саффрон

-4

Я хотел бы иметь класс в вашем 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

1
Вы уверены, что без! Важной линейки CLASS переопределит ID один?
DaneSoul

1
Да, так и будет, потому что теперь вы нацеливаетесь на # elem.no-transition, который является более конкретным, чем просто идентификатор
Мойн Заман

3
@MoinZaman Эээ, но вы не настроили таргетинг #elem.no-transitionна свой CSS, вы просто нацелились .no-transition. Возможно, вы хотели написать #elem.no-transitionв своем CSS?
Марк Амери
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.