浏览器渲染原理以及过程,重排与重绘

浏览器渲染过程

以webkit渲染引擎为例:
1,根据html文件构建DOM树
2,根据CSS文件构建CSSOM树
3,根据DOM树和CSSOM树构建渲染树
4,对渲染树进行布局
5,渲染树绘制显示
在这里插入图片描述

构建DOM树

浏览器受到服务器响应的html文档后,遍历文档节点,生成DOM树,但是在构建DOM树时可能因为js的加载而执行阻塞,在js文件执行完才继续构建DOM树
DOM树中的节点:script标签,注释等
display:none会在DOM树中

构建CSSOM树

浏览器解析css文件生成CSSOM规则树,每个css文件都被分析成一个stylesheet对象,每个对象都包含css规则,css规则对象包含对应于css语法的选择器和生命对象以及其他对象。
css解析和dom解析是同时进行的,且css解析于script执行互斥
无论是DOM树还是CSSOM规则树都要经过Bytes->characters->tokens->nodes->object model过程
在这里插入图片描述
在这里插入图片描述

当前节点所有子节点构建好后才会构建当前节点的下一个兄弟节点

构建渲染树

通过DOM树和CSSOM树,浏览器构建渲染树。浏览器先从DOM树的根节点开始遍历每一个可见节点,然后对每个可见节点找到适配的css样式规则并应用
渲染树和DOM树不完全对应
display:none的元素不会出现在渲染树中
visibility:hidden的元素在渲染树中
渲染树生成后无法渲染到屏幕,渲染屏幕需要各个节点的位置信息,就需要布局处理

渲染树布局

从渲染树的根节点开始遍历,由于渲染树的每个节点都有Render Object对象,包含宽高位置等样式信息,所以浏览器根据这些样式信息来确定每个节点对象的确切位置和大小,布局阶段的输出:盒子模型,能够精确的捕获每个元素在屏幕的确切位置和大小
脱离文档流:脱离了渲染树

渲染树绘制

浏览器遍历渲染树,调用渲染器的paint()方法在屏幕上显示内容,渲染树的绘制工作由浏览器的UI后端组件完成

浏览器渲染

浏览器主要组件结构

在这里插入图片描述

渲染引擎

五大浏览器:IE、Firefox、Safari、Chrome、Opera。
IE–Trident:  IE 是微软公司旗下浏览器
FF(Mozilla)–Gecko: Firefox 浏览器使 Mozilla 公司旗下浏览器
Safari–Webkit: 苹果公司发布的 Safari 浏览器
Chrome–BlinkWebKit 的分支) Chrome 浏览器是 Google 旗下的浏览器
Opera–原为 Presto,现为 Blink Opera 是挪威 Opera Software ASA 公司旗下的浏览器

五大浏览器采用的都是单内核,而随着浏览器的发展现在也出现了双内核。像 360 浏览器、QQ 浏览器都是采用双内核。

360 浏览器、猎豹浏览器内核:IE+Chrome 双内核;
搜狗、遨游、QQ 浏览器内核:Trident(兼容模式)+Webkit(高速模式);
百度浏览器:世界之窗内核+IE 内核;
2345 浏览器内核:以前是 IE 内核,现在也是 IE+Chrome 双内核;

渲染阻塞

由于js可以操作DOM修改DOM结构,操作CSSOM修改节点样式,导致遇到js时构建暂停,直到js执行完成才能继续构建。如果遇到脚本是外部的就会等待脚本下载完再继续解析。
现在可以再script标签上添加defer或者async,脚本解析会将脚本中改变DOM和CSSOM的地方分别解析出来,追加到DOM树和CSSOM规则树上。
js阻塞了DOM树构建和CSSOM规则树的构建,导致整个解析必须等js执行完才能继续,这就是js阻塞页面
由于CSSOM存储渲染信息,所以再渲染书合成前必须CSSOM和DOM完备,所以CSS都下载解析完。这就是CSS阻塞渲染
如果没有给页面任何样式,CSSOM也会生成,默认生成的CSSOM自带浏览器样式
再构建DOM树时,解析HTML文档,会把新的元素插入DOM树,同时查找CSS,把对应样式规则应用到元素上,查找样式表(从右到左顺序匹配,即.header  p{font-size:14px}会先找p,然后找header类来确定是否渲染)

回流(reflow,重排)和重绘(repaint)

回流(重排)

当浏览器布局发生改变,这时候需要倒回去重新渲染,这个回退过程叫回流(重排)。回流会从HTML这个root frame开始递归往下,依次计算所有节点的几何尺寸位置,确认渲染树的一部分发生发生变化还是真个渲染树发生变化。回流几乎无法避免

重绘

当改变某个元素的背景色,文字颜色,边框颜色等不影响周围或者内部的属性时,屏幕的一部分重画,但是元素的几何尺寸和位置没有改变

display:none触发重排,visibility:hidden只是隐藏但是任然占据位置,所以会导致重绘

有些修改了样式单不会立刻重绘或者重排一次,而是积攒这些操作,然后一次左重排,这叫异步重排或者增量异步重排。

引起重排

页面第一次渲染即初始化
DOM树发生改变(增删节点)
渲染树发生改变(位置发生改变)
浏览器窗口——resize事件发生时

引起重绘

重排一定会引起重绘
背景色,颜色,字体变化(字体大小变化会引起重排)

减少重排,重绘触发次数

1.直接改变className,如果动态改变样式,则使用cssText(考虑没有优化的浏览器);
2.让要操作的元素进行”离线处理”,处理完后一起更新;
a) 使用DocumentFragment进行缓存操作,引发一次回流和重绘;
b) 使用display:none技术,只引发两次回流和重绘;
c) 使用cloneNode(true or false) 和 replaceChild 技术,引发一次回流和重绘;
3.不要经常访问会引起浏览器flush队列的属性,如果你确实要访问,利用缓存;
4.让元素脱离动画流,减少回流的Render Tree的规模;

优化渲染效率

1合法地去书写HTML和CSS ,且不要忘了文档编码类型。
2样式文件应当在head标签中,而脚本文件在body结束前,这样可以防止阻塞的方式。
3简化并优化CSS选择器,尽量将嵌套层减少到最小。
4DOM 的多个读操作(或多个写操作),应该放在一起。不要两个读操作之间,加入一个写操作。
5如果某个样式是通过重排得到的,那么最好缓存结果。避免下一次用到的时候,浏览器又要重排。 6不要一条条地改变样式,而要通过改变class,或者csstext属性,一次性地改变样式。 7尽量用transform来做形变和位移 8尽量使用离线DOM,而不是真实的网页DOM,来改变元素样式。比如,操作Document Fragment对象,完成后再把这个对象加入DOM。再比如,使用cloneNode()方法,在克隆的节点上进行操作,然后再用克隆的节点替换原始节点。 9先将元素设为display: none(需要1次重排和重绘),然后对这个节点进行100次操作,最后再恢复显示(需要1次重排和重绘)。这样一来,你就用两次重新渲染,取代了可能高达100次的重新渲染。 10position属性为absolute或fixed的元素,重排的开销会比较小,因为不用考虑它对其他元素的影响。 11只在必要的时候,才将元素的display属性为可见,因为不可见的元素不影响重排和重绘。另外,visibility : hidden的元素只对重绘有影响,不影响重排。 12使用window.requestAnimationFrame()、window.requestIdleCallback()这两个方法调节重新渲染。