文章目录
一、前言
面试的时候经常被问到,css重排(Reflow)和重绘(Repaint)。从字面意思也可以理解重排是重新排列,重绘是重新,绘制。
二、相关概念
在了解Reflow和Repaint 之前我们需要了解以下几个概念。
2.1 Dom Tree
在讲解dom tree 之前应该了解一下什么是dom?
DOM 全称是 Document Object Model,
译为文档对象模型。请注意里面的对象两字。
每个HTML标签都是一个对象,嵌套的标签是闭合的子标签。
DOM 由此可以将一段HTML 代码表示为标签的树型结构。只要内容在html中就会加入到dom tree 中,包括注释。
每一个树的节点都是一个对象
document
— DOM 的“入口点”。- 标签节点
- 元素内的文本形成文本节点 标记为#text
一个文本节点只包含一个字符串,没有节点,是树的叶子
a. 特殊字符(,<head>
之前的空格和换行符均被忽略。)
1.特殊字符↵ (js 中为\n)
2.空格␣ - 注释节点类型(不会显示在dom中但是,js可以从dom中读取到)
示例:
<!DOCTYPE HTML>
<html>
<head>
<title>About elk</title>
</head>
<body>
The truth about elk.
</body>
</html>
dom树结构
2.2 Render Tree
在了解了Dom Tree 之后,我们就可以进阶一步了解Render Tree。
dom节点:
- 可视化节点(div p 等这种结构性标签)
- 非可视化节点(script meta 等在这种页面上显示不出来的节点)
浏览器获取 HTML 文件,然后对文件进行解析,形成DOM Tree
与此同时,进行 CSS 解析,生成 Style Rules
接着将 DOM Tree 与 Style Rules 合成为 Render Tree
元素在页面中布局,然后绘制
render 树就是根据 可视化节点 和 css 样式表 结合诞生出来的树;
注意:PS: display: none 的元素会出现在 DOM树 中,但不会出现在 render 树中;
三、什么是Reflow?
当Render Tree中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程称为回流。
引起回流的操作
- 页面首次渲染
- 浏览器窗口大小发生改变
- 元素尺寸或位置发生改变
- 元素内容变化(文字数量或图片大小等等)
- 元素字体大小变化
- 添加或者删除可见的
DOM
元素 - 激活
CSS
伪类(例如::hover
) - 查询某些属性或调用某些方法
一些常用且会导致回流的属性和方法:
clientWidth
、clientHeight
、clientTop
、clientLeft
offsetWidth
、offsetHeight
、offsetTop
、offsetLeft
scrollWidth
、scrollHeight
、scrollTop
、scrollLeft
scrollIntoView()
、scrollIntoViewIfNeeded()
getComputedStyle()
getBoundingClientRect()
scrollTo()
四、什么是Repaint?
当页面中元素样式的改变并不影响它在文档流中的位置时(例如:color
、background-color
、visibility
等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘。
当一个元素的外观发生改变的时候,但是并不改变布局,重新绘制元素的过程,叫做重绘。比如color
,background-color
,visibility
等相关元素背景,文字颜色,边框样式
五、重排和重绘的影响
在了解了回流和重绘的时候,我们可以得出。回流比重绘的代价要更高。
因为每次在回流操作中,都需要生成一次Render Tree。
现代浏览器会对频繁的回流或重绘操作进行优化:
浏览器会维护一个队列,把所有引起回流和重绘的操作放入队列中,如果队列中的任务数量或者时间间隔达到一个阈值的,浏览器就会将队列清空,进行一次批处理,这样可以把多次回流和重绘变成一次。
六、如何针对回流和重绘进行优化
6.1 css 方面
- 避免使用table布局
- 尽可能在dom树最末端改变class
- 将动画效果应用到position属性为absolute或者fixed的元素上。(如果需要重排,尽量做局部重拍,不影响其他元素)
- 避免使用css表达式 比如calc()
有关第三点,其实就是分层,将全局重排变为局部重排,但是会有
绘制可以将布局树中的元素分解为多个层。将内容提升到 GPU 上的层(而不是 CPU 上的主线程)可以提高绘制和重新绘制性能。有一些特定的属性和元素可以实例化一个层,包括
<video>
和<canvas>
,任何 CSS 属性为opacity
、3Dtransform
、will-change
的元素,还有一些其他元素。这些节点将与子节点一起绘制到它们自己的层上,除非子节点由于上述一个(或多个)原因需要自己的层。
分层确实可以提高性能,但是它以内存管理为代价,因此不应作为 web 性能优化策略的一部分过度使用。
6.2 js 方面
- 多个样式更改最好用一个calss去更改,
- 避免重复操作dom。可以将dom操作定义到一个变量中。最后添加到文本中
- 可以对元素初始属性设置display: none , 对dom操作结束再让其显示出来。因为修改display:none ,不会引起dom的重排和重绘制
七、总结
7.1 浏览器渲染
浏览器获取 HTML 文件,然后对文件进行解析,形成 [[DOM Tree]]
与此同时,进行 CSS 解析,生成 Style Rules
接着将 DOM Tree 与 Style Rules 合成为 Render Tree
元素在页面中布局,然后绘制
render 树就是根据 可视化节点 和 css 样式表 结合诞生出来的树;