暂时禁用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为目标并删除该类。这样就消除了*CSS 中令人讨厌的。
marcellothearcane

Answers:


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

或者这个带有jQuery的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/


8
出色的答案。做得很好,并感谢,因为我提出了同样的问题。如果我只想删除一种过渡类型怎么办?
rafaelmorais 2014年

2
您的解决方案是正确的,但对于那些寻求更多背景信息的人来说:stackoverflow.com/a/31862081/1026
Nickolay 2015年

2
除了较小的未成年人,IE10是IE的第一个稳定版本,附带无前缀的过渡。预发行版本(不包括发行预览)要求使用-ms-前缀进行转换,以及许多其他功能。我怀疑,这是-ms-前缀今天出现的原因之一。当然,另一个(更有可能是)原因是我们大家都知道并喜欢的关于供应商前缀的通常的货物崇拜。
BoltClock

1
有趣的是,仅检查元素的偏移高度会触发重排。希望我一年前就知道这个问题,当时我把头撞在墙上。仍然认为这是处理此问题的最理想方法吗?
Brett84c

2
在对不具有offsetHeight属性的SVG元素进行动画处理时,回流技巧似乎无效。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 2012年

对于只想一次全部完成的情况,这是正确的答案。例如,我想在移动设备上旋转时禁用过渡,这是完美的选择。
本拉赫曼

我最终在一个有点复杂的场景中在angularjs中使用了它,但是天哪,经过几天的努力,这很有帮助。
Aditya MP

2
性能方面,我绝对不能指望这是个好主意。“哦,只需将其应用于页面上的所有内容,这将使事情变得更加轻松!”
罗德韦克2014年

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 已添加以确保此规则将具有更多的“权重”,因为ID通常比类更具体。

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代码为页面中的所有元素禁用动画,过渡,变形

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块注入页面
Sam Saffron 2012年

3
您确定没有!important CLASS标尺会覆盖ID 1吗?
DaneSoul 2012年

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文件。如果您想在刮板(Ruby-Selenium)的上下文中使用它,这里还有一个github存储库:remove-CSS-animations-repo


-3

确实

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

在你的js里杀了吗?

显然每个重复。


1
那么您需要根据实际情况对其进行重置,因此需要对其进行存储,这将导致大量的锅炉板
Sam Saffron 2012年

-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
您确定没有!important CLASS标尺会覆盖ID 1吗?
DaneSoul 2012年

1
是的,它会因为现在你的目标#elem.no过渡这不仅仅是ID更具体的
莫恩扎曼

3
@MoinZaman Erm,但您没有#elem.no-transition在CSS中定位,只是定位了.no-transition。也许您打算用#elem.no-transitionCSS 编写?
马克·阿默里
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.