Який найчистіший спосіб тимчасово відключити ефекти переходу CSS?


209

У мене є елемент 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.
marcellothearcane

Відповіді:


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
Nickolay

2
Невеликий незначний вбік, IE10 був першою стабільною версією IE, що постачалася з нефіксованими переходами. Версії до випуску, за винятком попереднього попереднього випуску, вимагали префікса -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
Насправді це ідеальний варіант imo. Особливо * допомагає дуже багато, переконуючись, що жодна з додаткових анімацій не запускається. Дякую, підтримуємо.
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

За допомогою цього коду css можна відключити анімацію, перехід, trasform для всіх елементів сторінки

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
Ви впевнені, що без! Важливий лінійка класу замінить ідентифікатор один?
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 repo, якщо ви хочете використовувати це в контексті скрепера (Ruby-Selenium): delete-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
Ви впевнені, що без! Важливий лінійка класу замінить ідентифікатор один?
DaneSoul

1
Так, так, тому що зараз ви орієнтуєтесь на # elem.no-перехід, який є більш конкретним, ніж просто ідентифікатор
Moin Zaman

3
@MoinZaman Erm, але ви не зробили націлювання #elem.no-transitionна свій CSS, ви просто націлилися .no-transition. Можливо, ви мали намір писати #elem.no-transitionу своєму CSS?
Марк Амерді
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.