更改 CSS 时强制浏览器触发重排

Posted

技术标签:

【中文标题】更改 CSS 时强制浏览器触发重排【英文标题】:Force browser to trigger reflow while changing CSS 【发布时间】:2014-03-07 01:26:42 【问题描述】:

我正在构建基于 CSS3 过渡的非 jQuery 响应式图像滑块。

结构很简单:一个视口和内部相对定位的 UL,带有左浮动 LI。

在这种情况下我遇到了问题:

    用户点击“上一个”箭头。 JS 在当前显示的 LI 节点之前附加适当的 LI。 目前 UL 已将 CSS 过渡设置为 none 0s linear 以防止动画更改。在这一刻,我将 UL CSS 左值减小滑块宽度(假设:从 0px 到 -1200px)以使视图与原来相同。 现在我将 UL 的转换属性更改为 all 0.2s ease-out。 现在我正在更改 UL 的 left 属性以触发 CSS3 动画。 (假设:从 -1200px 到 0px)。

有什么问题?浏览器简化更改,不制作任何动画。

Stoyan Stefanov 在他的博客 here 上写了关于回流问题的文章,但在这种情况下,试图强制对元素进行回流是行不通的。

这是一段代码(为了简化,我跳过了浏览器前缀):

ul.style.transition = 'none 0s linear 0s'; ul.style.left = '-600px'; ul.style.transition = 'all 0.2s ease-out'; ul.style.left = '0px';

这里是查看实际问题的小提琴:http://jsfiddle.net/9WX5b/1/

【问题讨论】:

动画仅在 CSS 中的属性更改时发生。在您更改 left 属性之前,无需应用 none 0s linear 任何动画。 禁用过渡很重要,因为在添加新幻灯片后我必须不可见地修复旧幻灯片的位置。 "Force Reflow" in CSS transitions in Bootstrap的可能重复 【参考方案1】:

请求元素的offsetHeight 可以很好地完成所有工作。您可以使用此函数强制重排并将样式已更改的元素传递给它:

function reflow(elt)
    console.log(elt.offsetHeight);

在需要回流的地方调用它。看这个例子:http://jsfiddle.net/9WX5b/2/

编辑:最近需要这样做,并想知道是否有比 console.log 更好的方法。您不能只写elt.offsetHeight 作为它自己的语句,因为优化器(至少是Chrome 的)不会触发重排,因为它只是访问没有设置getter 的属性,甚至不需要评估它。所以,AFAIK 最便宜的方法是void(elt.offsetHeight),因为它不确定void 是否有副作用。 (可以被覆盖或其他东西,idk)。

【讨论】:

谢谢你,你拯救了我的一天!此外,我使用 translate3d(如果支持)来获得更流畅的动画,并且在任何浏览器中一切都像魅力一样。再次感谢。 您甚至不需要console.logelt.offsetHeight 就够了 在这里您可以找到一长串强制回流的属性和方法:gist.github.com/paulirish/5d52fb081b3570c81e3a 我认为不涉及 console.log() 的解决方案更好,因为它不会污染控制台。 @vaxquis 解决方案更好。 仅使用 offsetHeight 可能会被智能优化器编译出来。 Console.log 可能会阻止它,但也很嘈杂,也可以被删除。相反,您可以使用纪念品变量。这是一个轻微的内存泄漏,但如果你很聪明,你只会有一个。使用可写变量,您可以将其分配给自身。【参考方案2】:
function reflow( element ) 
    if ( element === undefined ) 
        element = document.documentElement;
    
    void( element.offsetHeight );

它适用于 Chrome 和 FF,似乎是最简单、最便携的 ATM 方式。

【讨论】:

以上是关于更改 CSS 时强制浏览器触发重排的主要内容,如果未能解决你的问题,请参考以下文章

Element.setAttribute 是不是触发重排?

仅当它们已更改时才强制浏览器重新加载 css/js

更改DOM后刷新浏览器悬停效果

上传新版本代码时如何强制浏览器清除缓存

为啥设置 textContent 会触发重排?

影响浏览器重绘和重排