关于重绘和回流

虽然只是浏览器渲染 HTML 的两个步骤,但是涉及到优化。

参考链接

浏览器的回流与重绘 (Reflow & Repaint)
前端性能优化:细说浏览器渲染的重排与重绘

一些说明

  • 为什么 DOM 操作很慢
    浏览器中会把 JavaScript 和 DOM 分开实现,虽然不同浏览器之间不同,举个例子,Chrome 里渲染使用的是 WebCore,而处理 JavaScript 是熟悉的 V8 引擎。
    而正因为 JavaScript 和 DOM 是分开实现的,所以每次使用 JavaScript 去操作 DOM 就需要在 JavaScript 和 DOM 之间建立连接。
    连理连接需要时间,而处理 DOM 也需要时间,所以 DOM 操作越多,付出的连接时间、处理时间也递增。

  • 输入 URL 到网页渲染之间发生了什么
    可以看这个 前端性能优化:细说浏览器渲染的重排与重绘
    还可以看这个里 关于 http 协议

  • 浏览器渲染 HTML 的步骤
    上面提到了 reflow 和 repaint 是渲染 HTML 的两个步骤而已,所以具体的步骤如下:

    1. HTML 被解析为 DOM Tree ,CSS 被解析为 CSSOM Tree
    2. DOM Tree 和 CSSOM Tree 整合为 Rander Tree
    3. 节点信息计算。在 webkit 中成为 layout,而在 Mozilla 里称 reflow
    4. 渲染绘制。成为 painting or repaint,绘制页面。

    但是 reflow 和 repaint 都是 re* ,而且网路上说法都有所差异,所以对于上诉步骤中(但是第一次渲染HTML确实是上诉的四步)对于 3/4 步能否称为 reflow 和 repaint 保留意见。 也有说法回流是第一次渲染的一部分,重绘不是的。 所以也不是很确定。但是不重要啦!第一次管他呢,看后面的重绘和回流。

回流和重绘的关系

回流一定会引发重绘;
重绘不一定有发生回流。

所以回流的成本一定会比回流高的。

也就是根据这一点,有了可以优化的地方。

重绘

元素的样式改变并不影响其在文档流中的位置时,浏览器会给予新的样式并重新绘制他,称为重绘。

不影响文档流中位置的样式就很多了,color/background/visibility/border-style/box-shadow 等。

回流

因为浏览器采用流式布局,当 Render Tree 中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程称为回流。

会引发变动的操作

  1. 首次渲染
  2. 浏览器窗口变动
  3. 元素尺寸/位置变动
  4. 元素内容(文字大小、数量/图片大小)变动
  5. 添加/删除 DOM 元素
  6. 激活伪类
  7. 设置 style 属性
  8. 查询某些属性或调用某些方法

第八条里的某些属性比如 client(offset/scroll)Width、client(offset/scroll)Height、client(offset/scroll)Top、client(offset/scroll)Left

第八条里的某些方法比如 scrollIntoView()、scrollIntoViewIfNeeded()、getComputedStyle()、getBoundingClientRect()、scrollTo()

优化问题

大概还是围绕避免回流和减少 DOM 操作这两点展开优化。

  • CSS
    避免设置多层内联样式,就是避免直接在标签上使用 style 属性。
    有动画的元素最好设置 ablsolute/fixed,不会影响到其他元素的布局。
    避免使用 table 布局,因为一部分内容变动,会导致整个 table 回流。
    屏幕滚动时/屏幕外的动画暂停。
    避免使用 CSS 表达式。
  • JavaScript
    减少操作节点 style 而使用增/删节点的 class 属性
    避免频繁使用 DOM
    也可以先对节点设置 display: none 操作结束后再显示出来,这样不会引发回流和重绘。
0%