虽然只是浏览器渲染 HTML 的两个步骤,但是涉及到优化。
参考链接
浏览器的回流与重绘 (Reflow & Repaint)
前端性能优化:细说浏览器渲染的重排与重绘
一些说明
为什么 DOM 操作很慢
浏览器中会把 JavaScript 和 DOM 分开实现,虽然不同浏览器之间不同,举个例子,Chrome 里渲染使用的是 WebCore,而处理 JavaScript 是熟悉的 V8 引擎。
而正因为 JavaScript 和 DOM 是分开实现的,所以每次使用 JavaScript 去操作 DOM 就需要在 JavaScript 和 DOM 之间建立连接。
连理连接需要时间,而处理 DOM 也需要时间,所以 DOM 操作越多,付出的连接时间、处理时间也递增。输入 URL 到网页渲染之间发生了什么
可以看这个 前端性能优化:细说浏览器渲染的重排与重绘
还可以看这个里 关于 http 协议浏览器渲染 HTML 的步骤
上面提到了 reflow 和 repaint 是渲染 HTML 的两个步骤而已,所以具体的步骤如下:- HTML 被解析为 DOM Tree ,CSS 被解析为 CSSOM Tree
- DOM Tree 和 CSSOM Tree 整合为 Rander Tree
- 节点信息计算。在 webkit 中成为 layout,而在 Mozilla 里称 reflow
- 渲染绘制。成为 painting or repaint,绘制页面。
但是 reflow 和 repaint 都是 re* ,而且网路上说法都有所差异,所以对于上诉步骤中(但是第一次渲染HTML确实是上诉的四步)对于 3/4 步能否称为 reflow 和 repaint 保留意见。 也有说法回流是第一次渲染的一部分,重绘不是的。 所以也不是很确定。但是不重要啦!第一次管他呢,看后面的重绘和回流。
回流和重绘的关系
回流一定会引发重绘;
重绘不一定有发生回流。
所以回流的成本一定会比回流高的。
也就是根据这一点,有了可以优化的地方。
重绘
元素的样式改变并不影响其在文档流中的位置时,浏览器会给予新的样式并重新绘制他,称为重绘。
不影响文档流中位置的样式就很多了,color/background/visibility/border-style/box-shadow 等。
回流
因为浏览器采用流式布局,当 Render Tree 中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程称为回流。
会引发变动的操作
- 首次渲染
- 浏览器窗口变动
- 元素尺寸/位置变动
- 元素内容(文字大小、数量/图片大小)变动
- 添加/删除 DOM 元素
- 激活伪类
- 设置 style 属性
- 查询某些属性或调用某些方法
第八条里的某些属性比如 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 操作结束后再显示出来,这样不会引发回流和重绘。