一.浏览器渲染页面的原理及流程
浏览器的核心部分是渲染引擎,也称为浏览器的内核,负责对网页语法(如HTML、CSS、JavaScript等)的解释并显示网页。Firefox使用Geoko——Mozilla自主研发的渲染引擎,Safari和Chrome使用webkit内核。 webkit引擎渲染流程 大概可以划分成以下几个步骤: (0)渲染引擎首先通过网络获得所请求文档的内容 (1)解析HTML文件,构建 DOM Tree (2)解析CSS,构建 CSSOM Tree(CSS规则树) (3)将 DOM Tree 和 CSSOM Tree合并,构建Render tree(渲染树) (4)reflow(重排):根据Render tree进行节点信息计算(Layout) (5)repaint(重绘):根据计算好的信息绘制整个页面(Painting) 注意:以上五个步骤并不一定一次性顺序完成,比如DOM或CSSOM被修改时,亦或是哪个过程会重复执行,这样才能计算出哪些像素需要在屏幕上进行重新渲染。而在实际情况中,JavaScript和CSS的某些操作往往会多次修改DOM或者CSSOM。 这个过程是逐步完成的,为了更好的用户体验,渲染引擎尽可能早的将内容呈现到屏幕上,并不会等到所有的html都解析完成之后再去构建和布局渲染树。它是解析一部分内容就显示一部分内容,同时,可能还在通过网络下载其余内容。
因为有时JS也参与DOM Tree的构建,因而我们会先执行js再开始构建渲染树。
所以说:JS脚本会阻塞Render tree的构建,即阻塞了页面的渲染。我们可以在把script脚本放于body后面,来解决上面的问题。
二.构建渲染树 Render tree
Render tree是由 DOM 和 CSSOM 组合构建而成的。也是页面可视化元素按照其显示顺序而组成的树。它的作用是让浏览器按照正确的顺序绘制内容。
Render Tree和DOM Tree不完全对应: 非可视化的 DOM 元素并不会全部插入Render tree中,像header元素和设置了display:none的元素 就不在渲染树中(但是 设置了visibility :hidden 的元素仍会显示在其中)。
三.渲染树布局-绘制
渲染树生成后,还是没有办法渲染到屏幕上,渲染到屏幕需要得到各个节点的位置信息,这就需要布局(Layout)的处理了。 布局阶段会从渲染树的根节点开始遍历,由于渲染树的每个节点都是一个Render Object对象,包含宽高,位置,背景色等样式信息。所以浏览器就可以通过这些样式信息来确定每个节点对象在页面上的确切大小和位置,布局阶段的输出就是我们常说的盒子模型,它会精确地捕获每个元素在屏幕内的确切位置与大小。需要注意的是:
float元素,absoulte元素,fixed元素会发生位置偏移。
我们常说的脱离文档流,其实就是脱离Render Tree。
在绘制阶段,浏览器会遍历渲染树,调用渲染器的paint()方法在屏幕上显示其内容。渲染树的绘制工作是由浏览器的UI后端组件完成的。
四.回流和重绘(reflow和repaint)
我们都知道HTML默认是流式布局的,但CSS和JS会打破这种布局,改变DOM的外观样式以及大小和位置。因此我们就需要知道两个概念:replaint和reflow。
3.1重绘(repaint): 渲染树节点发生改变,但不影响该节点在页面当中的空间位置及大小。譬如某个div标签节点的背景颜色、字体颜色等等发生改变,但是该div标签节点的宽、高、内外边距并不发生变化,此时触发浏览器重绘(repaint)。
3.2重排(reflow): 也有称回流,当渲染树节点发生改变,影响了节点的几何属性(如宽、高、内边距、外边距、或是float、position、display:none;等等),导致节点位置发生变化,此时触发浏览器重排(reflow),需要重新生成渲染树。譬如JS为某个p标签节点添加新的样式:“display:none;”。导致该p标签被隐藏起来,该p标签之后的所有节点位置都会发生改变。此时浏览器需要重新生成渲染树,重新布局,即重排(reflow)。
理论上,每一次的dom更改或者css几何属性更改,都会引起一次浏览器的重排/重绘过程,而如果是css的非几何属性更改,则只会引起重绘过程。所以说重排一定会引起重绘,而重绘不一定会引起重排。
五.何时会引起重排?
(1)页面首次渲染。 (2)元素尺寸改变——边距、填充、边框、宽度和高度 (3)元素位置改变——display、float、position、overflow等等; (4)内容改变——比如文本改变或者图片大小改变而引起的计算值宽度和高度改变; (5)操作DOM时;
六.减少重排,优化性能
(1)不要一个个的修改 DOM 的样式,应通过 class 来修改。 (2)实现元素的动画,它的position属性,最好是设为absoulte或fixed,这样不会影响其他元素的布局 (3)使用DocumentFragment将需要多次修改的DOM元素缓存,最后一次性append到真实DOM中渲染 (4)可以将需要多次修改的DOM元素设置display:none,操作完再显示。(因为隐藏元素不在render树内,因此修改隐藏元素不会触发回流重绘)
可以参考链接: https://www.cnblogs.com/chenyoumei/p/9156849.html https://www.jianshu.com/p/e6252dc9be32
|