作者:贝程学院
浏览器内核分为两部分:渲染引擎(Layout Engine 或者 Rendering Engine)和 JS 引擎。早期渲染引擎和 JS 引擎并没有明显区分,随着 JS 引擎越来越独立,内核逐渐变成了渲染引擎的代名词。渲染引擎包括:
- HTML 解释器
- CSS 解释器
- 布局
- 网络
- 存储
- 图形
- 音视频
- 图片解码器
- 等等
渲染引擎简介
浏览器——Firefox、Chrome和Safari是基于两种渲染引擎构建的,Firefox使用Geoko——Mozilla自主研发的渲染引擎,Safari和Chrome都使用webkit。
Webkit是一款开源渲染引擎,它本来是为Linux平台研发的,后来由Apple移植到Mac及Windows上
一.基本概念
- DOM:Document Object Model,浏览器将HTML解析成树形的数据结构,简称DOM。
- CSSOM:CSS Object Model,浏览器将CSS解析成树形的数据结构,简称CSSOM。
- Render Tree: DOM和CSSOM合并后生成Render Tree。
- Layout: 计算出Render Tree每个节点的具体位置。
- Painting:通过显卡,将Layout后的节点内容分别呈现到屏幕上。
二.浏览器页面渲染和浏览器工作过程
页面渲染是浏览器将html代码根据CSS定义的规则显示在浏览器窗口中的过程。
了解浏览器的基本工作过程:
- 用户输入网址(假设是html页面,并且是第一次访问),浏览器向服务器发出请求,服务器返回html文件;
- 浏览器开始载入html代码,发现<head>标签内有一个<link>标签引用外部CSS文件;
- 浏览器又发出CSS文件的请求,服务器返回这个CSS文件; 浏览器又发出CSS文件的请求,服务器返回这个CSS文件;
- 浏览器继续载入html中<body>部分的代码,并且CSS文件已经拿到手了,可以开始渲染页面了;
- 浏览器在代码中发现一个<img>标签引用了一张图片,向服务器发出请求。此时浏览器不会等到图片下载完,而是继续渲染后面的代码;
- 服务器返回图片文件,由于图片占用了一定面积,影响了后面段落的排布,因此浏览器需要回过头来重新渲染这部分代码;
- 浏览器发现了一个包含一行Java代码的<>标签,赶快运行它;
- Java脚本执行了这条语句,它命令浏览器隐藏掉代码中的某个<div> (style.display=”none”)。杯具啊,突然就少了这么一个元素,浏览器不得不重新渲染这部分代码; 终于等到了</html>的到来,浏览器泪流满面……
- 等等,还没完,用户点了一下界面中的“换肤”按钮,Java让浏览器换了一下<link>标签的CSS路径;
- 浏览器召集了在座的各位<div><span><ul><li>们,“大伙儿收拾收拾行李,咱得重新来过……”,浏览器向服务器请求了新的CSS文件,重新渲染页面 。
三.渲染引擎的两个主要工作过程:解析过程和渲染过程
A.浏览器解析过程
- 浏览器通过请求的 URL 进行域名解析,向服务器发起请求,接收文件(HTML、CSS、JS、Images等等)。
- HTML 文件加载后,开始构建 DOM Tree
- CSS 样式文件加载后,开始解析和构建 CSS Rule Tree
- Java 脚本文件加载后, 通过 DOM API 和 CSSOM API 来操作 DOM Tree 和 CSS Rule Tree
解析一个文档即将其转换为具有一定意义的结构——编码可以理解和使用的东西。解析的结果通常是表达文档结构的节点树,称为解析树或语法树。
B.浏览器渲染过程
- 浏览器引擎通过 DOM Tree 和 CSS Rule Tree 构建 Rendering Tree,Rendering Tree 并不与 DOM Tree 对应,比如像标签内容或带有 display: none; 的元素节点并不包括在 Rendering Tree 中 。
- 通过 CSS Rule Tree 匹配 DOM Tree 进行定位坐标和大小,是否换行,以及 position、overflow、z-index 等等属性,这个过程称为 Flow 或 Layout 。
- 最终通过调用Native GUI 的 API 绘制网页画面的过程称为 Paint 。
三.渲染过程中涉及到的树
- DOM 树:解析 HTML 以创建的是 DOM 树(DOM tree ):渲染引擎开始解析 HTML 文档,转换树中的标签到 DOM 节点,它被称为“内容树”。
- CSSOM 树:解析 CSS(包括外部 CSS 文件和样式元素)创建的是 CSSOM 树。CSSOM 的解析过程与 DOM 的解析过程是并行的。
- 渲染树:CSSOM 与 DOM 结合,之后我们得到的就是渲染树(Render tree )。
- 布局渲染树:从根节点递归调用,计算每一个元素的大小、位置等,给每个节点所应该出现在屏幕上的精确坐标,我们便得到了基于渲染树的布局渲染树(Layout of the render tree)。
- 绘制渲染树: 遍历渲染树,每个节点将使用 UI 后端层来绘制。整个过程叫做绘制渲染树(Painting the render tree)。
四.渲染树和Dom树的关系
在DOM树构建的同时,浏览器会构建渲染树(render tree)。渲染树的节点(渲染器),在Gecko中称为frame,而在webkit中称为renderer。渲染器是在文档解析和创建DOM节点后创建的,会计算DOM节点的样式信息。
在webkit中,renderer是由DOM节点调用attach()方法创建的。attach()方法计算了DOM节点的样式信息。attach()是自上而下的递归操作。也就是说,父节点总是比子节点先创建自己的renderer。销毁的时候,则是自下而上的递归操作,也就是说,子节点总是比父节点先销毁。
渲染对象和Dom元素对应关系不是一对一的,不可见的Dom元素不会被插入渲染树,例如head元素。另外,display属性为none的元素也不会在渲染树中出现(visibility属性为hidden的元素将出现在渲染树中)。
还有一些Dom元素对应几个可见对象,它们一般是一些具有复杂结构的元素,无法用一个矩形来描述。例如,select元素有三个渲染对象——一个显示区域、一个下拉列表及一个按钮。同样,当文本因为宽度不够而折行时,新行将作为额外的渲染元素被添加。另一个多个渲染对象的例子是不规范的html,根据css规范,一个行内元素只能仅包含行内元素或仅包含块状元素,在存在混合内容时,将会创建匿名的块状渲染对象包裹住行内元素。
一些渲染对象和所对应的Dom节点不在树上相同的位置,例如,浮动和绝对定位的元素在文本流之外,在两棵树上的位置不同,渲染树上标识出真实的结构,并用一个占位结构标识出它们原来的位置。
DOM树和渲染树的对应关系如下图:
五 . 为什么了解浏览器渲染原理/机制
页面为什么会慢?因为浏览器要花时间、花精力去渲染,尤其是当它发现某个部分发生了点变化影响了布局,需要倒回去重新渲染,这个回退过程叫reflow。
reflow几乎是无法避免的。现在界面上流行的一些效果,比如树状目录的折叠、展开(实质上是元素的显示与隐藏)等,都将引起浏览器的 reflow。鼠标滑过、点击……只要这些行为引起了页面上某些元素的占位面积、定位方式、边距等属性的变化,都会引起它内部、周围甚至整个页面的重新渲染。通常我们都无法预估浏览器到底会reflow哪一部分的代码,它们都彼此相互影响着。
所以有必要了解浏览器的渲染原理:
- 了解浏览器加载过程,前端开发在引用外部style文件和外部JS时,将它们放到合适的位置,浏览器可以以最快的速度,将文件加载完毕;
- 了解浏览器解析过程/原理,前端开发人员可以在构建DOM结构,组织CSS选择器的时候,选择最优的写法,提高浏览器的解析速率;
- 了解浏览器渲染过程,明白渲染的过程,前端开发在设置元素属性,编写JS文件时,可以减少“重绘”,“重新布局”的消耗。
了解浏览器渲染原理/机制目的是为了性能优化
六.如何减少回流和重绘
1.重绘(Repaint)和回流(Reflow)
当第一次打开一个页面时,至少会有一次重绘和回流。之后,如果渲染树发生了变动,那么可能会触发重绘或回流中的一个或二者。
如果渲染树的结点发生了结构性变化,例如宽度、高度或者位置上的变化时,那么会触发Reflow(回流)的逻辑。我们第一次进入一个页面时便会至少触发一次这个逻辑。
如果渲染树结点发生了非结构性变化,例如背景色等的变化时,那么会触发Repaint(重绘)的逻辑。
2.重绘(Repaint)和回流(Reflow)的区别
- Repaint ——改变某个元素的背景色、文字颜色、边框颜色等等不影响它周围或内部布局的属性时,屏幕的一部分要重画,但是元素的几何尺寸没有变。
- Reflow ——元件的几何尺寸变了,我们需要重新验证并计算Render Tree。是Render Tree的一部分或全部发生了变化。
- reflow 几乎是无法避免的。现在界面上流行的一些效果,比如树状目录的折叠、展开(实质上是元素的显 示与隐藏)等,都将引起浏览器的 reflow。鼠标滑过、点击……只要这些行为引起了页面上某些元素的占位面积、定位方式、边距等属性的变化,都会引起它内部、周围甚至整个页面的重新渲 染。通常我们都无法预估浏览器到底会 reflow 哪一部分的代码,它们都彼此相互影响着。
- 注:display:none会触发reflow,而visibility:hidden只会触发repaint,因为没有发现位置变化。
3.如何降低Reflow对性能的影响
- 批量修改DOM 样式。预先定义好 css 的 class,只要修改 DOM 的 className,即将多次改变样式属性的操作合并为一次操作:
- ”离线处理”需要操作的元素,处理完成后一起更新。(使用DocumentFragment进行缓存操作,引发一次回流和重绘;使用display:none技术,引发两次回流和重绘;)
- 不要用tables布局。因为tables中某个元素一旦触发reflow就会导致table里所有元素reflow。在使用table的场景中,设置table-layout为auto或fixed,目的是让table助逐行渲染,还有就是限制了reflow的影响范围。
- css中不使用表达式expression
- 降低频繁增加,修改,删除元素的次数,因为这种操作会频繁的引起页面reflow,可以先将该dom节点抽离到内存中进行复杂的操作然后再display到页面上。
- 请求offsetTop, offsetLeft, offsetWidth, offsetHeight,scrollTop/Left/Width/Height,clientTop/Left/Width/Height,会引起浏览器会reflow,建议将它们合并到一起操作,可以减少回流的次数。
原文地址:https://www.cnblogs.com/beichengjiaoyu/p/11641352.html