回流和重绘

回流是计算元素在视口内的位置和大小,重绘是将渲染树转换为屏幕像素的过程。回流会触发重绘,但反之不成立。浏览器采用优化策略批量处理样式修改,但某些操作如获取布局信息会触发即时回流。减少回流和重绘的方法包括:在DOM树末端改变class、避免多层内联样式、使用position: absolute或fixed的动画、牺牲平滑度换取速度、避免table布局和CSS JavaScript表达式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

回流(重构/重排/reflow)

DOM树和CSSOM树结合后的渲染树后,将可见DOM节点以及它对应的样式结合起来,可是我们还需要计算它们在设备视口(viewport)内的确切位置和大小,这个计算的阶段就是回流。

重绘(repaint或redraw)

通过构造渲染树和回流阶段,我们知道了哪些节点是可见的,以及可见节点的样式和具体的几何信息(位置、大小),那么我们就可以将渲染树的每个节点都转换为屏幕上的实际像素,这个阶段就叫做重绘节点。

 

 

 

回流一定会触发重绘,而重绘不一定会回流

例如background-color等不关于页面结构布局的变化就不会产生回流

 

 

浏览器的优化机制

现代的浏览器都是很聪明的,由于每次重排都会造成额外的计算消耗,因此大多数浏览器都会通过队列化修改并批量执行来优化重排过程。浏览器会将修改操作放入到队列里,直到过了一段时间或者操作达到了一个阈值,才清空队列。但是!当你获取布局信息的操作的时候,会强制队列刷新,比如当你访问以下属性或者使用以下方法:

  • offsetTop、offsetLeft、offsetWidth、offsetHeight
  • scrollTop、scrollLeft、scrollWidth、scrollHeight
  • clientTop、clientLeft、clientWidth、clientHeight
  • getComputedStyle()
  • getBoundingClientRect
  • 具体可以访问这个网站:gist.github.com/paulirish/5…

以上属性和方法都需要返回最新的布局信息,因此浏览器不得不清空队列,触发回流重绘来返回正确的值。因此,我们在修改样式的时候,最好避免使用上面列出的属性,他们都会刷新渲染队列。

 

 

如何减少回流和重绘

 

1. 尽可能在DOM树的最末端改变class

回流可以自上而下,或自下而上的回流的信息传递给周围的节点。回流是不可避免的,但可以减少其影响。尽可能在DOM树的里面改变class,可以限制了回流的范围,使其影响尽可能少的节点。例如,你应该避免通过改变对包装元素类去影响子节点的显示。面向对象的CSS始终尝试获得它们影响的类对象(DOM节点或节点),但在这种情况下,它已尽可能的减少了回流的影响,增加性能优势。

2. 避免设置多层内联样式

我们都知道与DOM交互很慢。我们尝试在一种无形的DOM树片段组进行更改,然后整个改变应用到DOM上时仅导致了一个回流。同样,通过style属性设置样式导致回流。避免设置多级内联样式,因为每个都会造成回流,样式应该合并在一个外部类,这样当该元素的class属性可被操控时仅会产生一个reflow。

3. 动画效果应用到position属性为absolute或fixed的元素上

动画效果应用到position属性为absolute或fixed的元素上,它们不影响其他元素的布局,所它他们只会导致重新绘制,而不是一个完整回流。这样消耗会更低。

4. 牺牲平滑度换取速度

Opera还建议我们牺牲平滑度换取速度,其意思是指您可能想每次1像素移动一个动画,但是如果此动画及随后的回流使用了100%的CPU,动画就会看上去是跳动的,因为浏览器正在与更新回流做斗争。动画元素每次移动3像素可能在非常快的机器上看起来平滑度低了,但它不会导致CPU在较慢的机器和移动设备中抖动。

5. 避免使用table布局

避免使用table布局。可能您需要其它些避免使用table的理由,在布局完全建立之前,table经常需要多个关口,因为table是个和罕见的可以影响在它们之前已经进入的DOM元素的显示的元素。想象一下,因为表格最后一个单元格的内容过宽而导致纵列大小完全改变。这就是为什么所有的浏览器都逐步地不支持table表格的渲染(感谢Bill Scott提供)。然而有另外一个原因为什么表格布局时很糟糕的主意,根据Mozilla,即使一些小的变化将导致表格(table)中的所有其他节点回流。

6. 避免使用CSS的JavaScript表达式

这项规则较过时,但确实是个好的主意。主要的原因,这些表现是如此昂贵,是因为他们每次重新计算文档,或部分文档、回流。正如我们从所有的很多事情看到的:引发回流,它可以每秒产生成千上万次。当心!

即使使用到的时候也要避免触发同步布局事件

上文我们说过,当我们访问元素的一些属性的时候,会导致浏览器强制清空队列,进行强制同步布局。举个例子,比如说我们想将一个p标签数组的宽度赋值为一个元素的宽度,我们可能写出这样的代码:

function initP() {
    for (let i = 0; i < paragraphs.length; i++) {
        paragraphs[i].style.width = box.offsetWidth + 'px';
    }
}

这段代码看上去是没有什么问题,可是其实会造成很大的性能问题。在每次循环的时候,都读取了box的一个offsetWidth属性值,然后利用它来更新p标签的width属性。这就导致了每一次循环的时候,浏览器都必须先使上一次循环中的样式更新操作生效,才能响应本次循环的样式读取操作。每一次循环都会强制浏览器刷新队列。我们可以优化为:

const width = box.offsetWidth;
function initP() {
    for (let i = 0; i < paragraphs.length; i++) {
        paragraphs[i].style.width = width + 'px';
    }
}

 

 

 

 

参考文章

https://juejin.im/post/5c6cb7b4f265da2dae511a3d

https://blog.youkuaiyun.com/oscar999/article/details/38379523


 

 

 

### 浏览器渲染中的回流 #### 回流(Reflow) 回流是指当 DOM 的结构或元素的几何属性(如大小、位置等)发生变化时,浏览器需要新计算这些元素的位置尺寸,并更新整个页面布局的过程。这一过程通常涉及多个节点的新计算以及可能引发后续子树的调整[^1]。 例如,如果动态改变了某个元素的高度或者宽度,或者是隐藏了一个可见的元素,则会触发回流操作。每次回流都会带来一定的性能开销,尤其是复杂的布局场景下更为显著[^5]。 #### (Repaint) 相比之下,指的是由于某些视觉样式的更改而不需要改变文档流的情况下发生的制行为。比如颜色的变化、背景图片替换等情况只会导致像素级别的刷新而不影响整体布局结构[^3]。 需要注意的是,尽管单独来看似乎比回流轻量级一些,但如果频繁发生也可能累积成较大的性能瓶颈[^2]。 #### 主要区别 | 特性 | 回流 | | |--------------|-------------------------------|-------------------------| | **定义** | 布局变化引起的新计算 | 只有外观上的变动 | | **触发条件** | 修改了影响布局的因素 | 改变了不影响布局的样式 | | **范围** | 影响较大 | 较小 | | **频率控制** | 应尽量减少 | 同理需加以管理 | 为了提升网页加载速度并改善用户体验,在开发过程中应当采取措施来降低不必要的回流事件的发生几率。可以通过批量处理DOM变更动作、使用虚拟dom技术等方式实现优化目的;另外还可以考虑采用GPU加速特性明显的 CSS 属性如 `transform` `opacity`, 这些不会引起常规意义上的reflow/repaint流程而是交由更高效的图形处理器完成相应工作[^4]。 ```javascript // 减少回流的一个例子:先移除元素再做多次修改最后放回去 let parentElement = document.getElementById('parent'); let childToModify = document.createElement('div'); childToModify.style.width = '200px'; childToModify.style.height = '200px'; childToModify.style.backgroundColor = '#ff0000'; parentElement.appendChild(childToModify); ``` 上述代码展示了如何通过创建新节点而非直接操作现有DOM节点的方式来避免连续性的回流问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值