浏览器的重绘和回流
浏览器的重绘与回流
这是我在之前面试中遇到的一个问题,今天回想起来正好做一个总结
浏览器在将页面展示给我们之前都做了什么(渲染机制)
这其实也是我遇到的一道面试题,与重绘和回流息息相关
- 用户输入网址
- 浏览器通过DNS获取网站的IP地址
- 浏览器尝试与服务器建立连接
- 服务器发送永久重定向
- 浏览器跟踪重定向地址
- 服务器处理请求
- 服务器发送HTML响应
- 浏览器接收响应,开始解析
- 解析
html
文件,处理并创建DOM
树 - 解析
css
样式表, 构建CSSOM
树 - 将
DOM
与CSSOM
进行结合,构建渲染树(Render Tree) - 根据渲染树来布局(layout),计算每一个节点的位置
- 调用GPU进行绘制(Paint),合成图层
- 重绘(repaint)与回流(reflow)
当html
解析遇到script
时会暂停构建DOM,执行js脚本,执行完毕后才会继续构建DOM树,因此将js文件放在html
文件底部进行加载才会节省加载时间,加快绘制速度
浏览器使用流式布局 (Flow Based Layout),对Render Tree的计算通常只需要遍历一次就可以完成,但table及其内部元素除外,他们可能需要多次计算,通常要花3倍于同等元素的时间,这也是为什么要避免使用table布局的原因之一
重绘与回流
回流必将引起重绘,而重绘不一定引起回流
回流
当Render Tree
中部分或全部元素的尺寸、结构、布局、隐藏等发生改变而需要重新构建,浏览器因此重新渲染的过程叫做回流
会导致回流的操作:
- 页面的首次渲染
- 浏览器窗口哦的大小发生改变
- 元素的尺寸或位置发生改变
- 元素的内容发生变化
- 元素样式发生改变(字体、隐藏等)
- 激活CSS伪类(
:after
,:before
,:hover
等) - 调用某些方法
常用且会导致回流的属性和方法:
clientWidth
、clientHeight
、clientTop
、clientLeft
offsetWidth
、offsetHeight
、offsetTop
、offsetLeft
scrollWidth
、scrollHeight
、scrollTop
、scrollLeft
scrollIntoView()
、scrollIntoViewIfNeeded()
getComputedStyle()
getBoundingClientRect()
scrollTo
重绘
当页面元素的样式发生改变且并不影响它在文档中的位置时,浏览器将根据其新属性进行重新绘制,这个过程就是重绘
性能影响
回流比重绘更加影响性能,付出代价更高
有时即使仅仅回流一个单一的元素,它的父元素以及任何跟随它的元素也会产生回流。
现代浏览器会对频繁的回流或重绘操作进行优化:
浏览器会维护一个队列,把所有引起回流和重绘的操作放入队列中,如果队列中的任务数量或者时间间隔达到一个阈值的,浏览器就会将队列清空,进行一次批处理,这样可以把多次回流和重绘变成一次。
避免的方法
css
- 避免使用
table
布局 - 尽可能在DOM的末端改变
class
- 避免使用多层内联样式
- 将动画效果应用到
position
属性为absolute
或fixed
的元素上 - 避免使用
css
表达式(例如:calc()
)
Js
- 避免频繁地操作样式,尽可能地一次性重写style属性
- 避免频繁操作DOM,可以创建一个
documentFragment
,在其上完成所有DOM操作,然后将其加入到文档中 - 也可以先为元素设置
display: none
,操作结束后再把它显示出来。因为在display
属性为none
的元素上进行的DOM操作不会引发回流和重绘。 - 避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。
- 对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 幻尘の屋!
评论