暂时禁用 CSS 过渡效果的最干净方法是什么?

IT技术 javascript jquery css
2021-02-04 16:58:54

我有一个应用了以下部分/所有效果的 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 插件,我需要暂时禁用这些效果,以便我可以顺利调整它的大小。

考虑到它们可能从父母那里应用或根本不应用,暂时禁用这些效果(然后重新启用它们)的最优雅的方法是什么。

6个回答

简答

使用这个 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

或者这个带有 jQ​​uery 的 JS ......

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

...或使用您正在使用的任何其他库或框架的等效代码。

解释

这实际上是一个相当微妙的问题。

首先,您可能想要创建一个“notransition”类,您可以将其应用于元素以将其*-transitionCSS 属性设置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' 类的删除包装在 1ms 超时内,如下所示:

// 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 在重排之前执行排队功能。

我发现该问题的唯一解决方案是在删除“notransition”类之前强制重排元素,刷新对其所做的 CSS 更改。有多种方法可以做到这一点 - 请参阅此处了解一些信息。最接近“标准”的方法是读取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/

除了次要的小问题,IE10 是第一个带有无前缀转换的稳定版 IE。预发布版本(不包括发布预览版)需要 -ms- 前缀用于转换,以及许多其他内容。我怀疑,这就是 -ms- 前缀今天出现的原因之一。另一个,当然更有可能的原因是我们都知道并喜欢供应商前缀的常见货物崇拜。
2021-03-21 16:58:54
有趣的是,简单地检查元素的偏移高度会触发回流。希望我在一年前知道这一点,当时我正用同样的问题把头撞在墙上。这仍然被认为是最理想的处理方式吗?
2021-03-30 16:58:54
优秀的回答。干得好,很感激,因为我想出了同样的问题。如果我只想删除一种类型的过渡怎么办?
2021-04-01 16:58:54
您的解决方案是正确的,但对于那些寻找更多背景信息的人:stackoverflow.com/a/31862081/1026
2021-04-05 16:58:54
为没有 offsetHeight 属性的 SVG 元素设置动画时,回流技巧似乎不起作用;setTimeout 有效。
2021-04-10 16:58:54

添加一个额外的 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添加是为了确保此规则具有更高的优先级,因为使用 id 比使用类更具体。

查询

$('#elem').addClass('notransition'); // to remove transition
$('#elem').removeClass('notransition'); // to return to previouse transition
-1 因为这不足以在 Chrome 或 Firefox 中为我解决问题 - 如果我有添加类、进行更改并删除类的 Javascript,有时更改仍然具有动画效果。我花了最后一两个小时详细研究了这个问题,稍后将发布一个答案,并附上显示幼稚方法失败的情况的小提琴,加上一个巧妙的技巧,通过在进行更改和删除之间强制重排来修复这里的解决方案'notransition' 类。
2021-03-16 16:58:54
我建议不要使用 !important 除非你绝对必须。它会在以后引起很多头痛。我在没有它的情况下尝试过这个,只要你遵循 CSS 的级联规则,它仍然可以正常工作。
2021-04-07 16:58:54

我主张按照 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');
实际上,这是 imo 的完美选择。特别是 * 有很大帮助,确保没有触发任何子动画。谢谢,点赞。
2021-03-13 16:58:54
对于您只想一次性完成所有操作的情况,这是正确的答案。例如,我想在移动设备上旋转时禁用过渡,这非常适合。
2021-03-14 16:58:54
性能方面,我完全不能指望这会是个好主意。“哦,只需将其应用于页面上的所有内容,这会让事情变得更容易!”
2021-03-21 16:58:54
我建议不要使用 !important 除非你绝对必须。它会在以后引起很多头痛。我在没有它的情况下尝试过这个,只要你遵循 CSS 的级联规则,它仍然可以正常工作。
2021-03-24 16:58:54
可能应该同时选择“.notransition”和“.notransition *”才能完全有效。
2021-03-29 16:58:54

对于纯JS的解决方案(CSS无类),只需设置transition'none'要恢复 CSS 中指定的过渡,请将 设置transition为空字符串。

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

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

如果您使用供应商前缀,您也需要设置它们。

elem.style.webkitTransition = 'none'

您可以使用此 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);
@Golly 其他属性可能会影响最终设计
2021-03-21 16:58:54
首先这太棒了,谢谢!其次还有一些其他的属性应该被设置;参见github.com/japgolly/test-state/blob/master/util/shared/src/test/...
2021-03-25 16:58:54