浏览器渲染机制
浏览器首先通过网络加载模块加载页面代码与样式表,我们这里不考虑js文件阻塞问题(为什么阻塞:因为js文件里面可能会有修改页面结构的代码,所以要阻塞住,等待js执行完。)。
加载完页面代码与样式表,解析页面代码生成DOM节点树与样式表,生成css树。然后根据css树上的描述信息将DOM节点树合并到一张RenderTree上。接着将渲染树送入GPU绘制出一个可见的网页。(小知识:一个网页必定会重排一次)
<html>
<body>
<h1>我是标题</h1>
<div>
<p>我是正文</p>
<img src='xxx'/>
</div>
</body>
</html>
h1{font-size:30px;color:#ccc}
p{padding-top:30px;}
div img{border:0px;}
(DOM树)
DOM Tree是从Html节点开始(偷懒,没画)。DOM Tree构建流程: 解码->分词->解析->建树
(CSS树)
(渲染树) 主要记录了文档中每个节点的布局与渲染方式。
合成渲染树流程,计算所有元素坐标->计算元素外观->生成渲染树
浏览器同步创建DOMTree,CSSTree,RenderTree。根据这三颗Tree创建RenderLayerTree。 一般是通过 前三颗树创建出渲染层树,第一次重排是因为要计算所有网页的布局坐标大小。计算完成之后,会进行重绘。如果没有涉及到布局相关的,也就是不需要重新计算Layout的,浏览器直接调用重绘,跳过重排,解决问题。
什么是重排(REFLOW)
浏览器是根据送入的渲染树进行绘制这个网页,你所看到的网页其实本质是一个图片。那么每个元素都拥有自己所在的坐标。
重排,就是 这个元素的几何属性或者坐标发生了改变,所以会造成重排,其实就是浏览器因为几何变化造成这个变化的节点会影响到所有节点的坐标,从而需要重新计算所有渲染树上元素的坐标,所以才需要重排所有节点以便gpu重新绘制。重排在我看来主要是需要重新计算每个节点绘制的坐标造成的(为了重新生成RenderLayerTree)。
什么是重绘(REPAINT)
至于重绘我认为是浏览器的一种优化。因为所有元素的坐标是已经确定的了,重绘涉及的东西只是外观。也就是说。浏览器只需要重新与gpu描述一下此区域内的新外观表现,为什么呢?因为这样gpu只需要擦除这个区域内的图像重新绘制即可,而不用重新绘制所有元素。(此描述仅仅为一家之言)
什么情况下造成重排
只要涉及到盒模型的css属性基本都会造成重排,比如height,width,padding,border等。
另外以下属性会让浏览器立刻重排,为什么呢?因为重排并不是立刻产生作用的,浏览器有自身的优化手段。
offsetTop, offsetLeft, offsetWidth, offsetHeight
scrollTop/Left/Width/Height
clientTop/Left/Width/Height
getComputedStyle(), or currentStyle in IE
请求这些属性之前,如果有修改css盒模型,就会造成浏览器立刻重排以便计算最新属性。
什么情况下造成重绘
不影响css盒模型的属性只会造成重绘
如何优化
- 不单独设置css属性,如
document.body.style.width='100px';
- 如果一定通过js修改样式有以下两种方法
document.body.style.cssText=''; // 一次性修改 document.body.className = 'newClass'; // 修改class来实现最小次数重排
- 通过display:none来将节点脱离文档流,在修改完节点之后再显示,这样只有隐藏,显示两次。
- 将会立刻造成重排的属性数据存入临时变量中。
- position:absolute,fixed 会将节点脱离文档流,避免整个dom tree重排
- 移动通过translate来实现
- 浏览器原理中,(root节点,css position:relative,absolute,transform,有节点溢出overflow, alpha mask, reflection,css filter,2dCanvas,WebGl,video)都会为这些元素创造一个新的Layer以便浏览器加速渲染,这些元素的修改只会涉及自己重排重绘。
如果有更多的优化手段会补充进来。
参考资料
减少页面回流与重绘(Reflow & Repaint) | Harttle Land
Minimizing browser reflow | PageSpeed Insights | Google Developers
#前端
© 2017 写代码的熊猫,浙ICP备09026245号,当前系统遵从Apache License开源协议开源, [GITHUB SOURCE]