浏览器渲染

浏览器

浏览器基础结构主要包括以下7部分:
 
1.用户界面(User Interface):用户所看到及与之交互的功能组件,如地址栏,返回,前进按钮等;
2.浏览器引擎(Browser engine):负责控制和管理下一级的渲染引擎;
3. 渲染引擎(Rendering engine):负责解析用户请求的内容(如HTML或XML,渲染引擎会解析HTML或XML,以及相关CSS,而后返回解析后的内容);
4.网络(Networking):负责处理网络相关的事务,如HTTP请求等;
5.UI后端(UI backend):负责绘制提示框等浏览器组件,其底层使用的是操做系统的用户接口;
6. JavaScript解释器(JavaScript interpreter):负责解析和执行JavaScript代码;
7.数据存储(Data storage):负责持久存储诸如cookie和缓存等应用数据。
 
浏览器内核
浏览器内核主要指的是浏览器的渲染引擎,各大主要浏览器使用内核也是有差异的,大体能够分为如下几类:
  • Trident内核: IE
  • Webkit内核:Chrome,Safari
  • Gecko内核:FireFox
 
关于移动端
移动端的浏览器内核主要说的是系统内置浏览器的内核。
目前移动设备浏览器上经常使用的内核有 Webkit,Blink,Trident,Gecko 等,其中 iPhone 和 iPad 等苹果 iOS 平台主要是 WebKit,Android 4.4 以前的 Android 系统浏览器内核是 WebKit,Android4.4 系统浏览器切换到了Chromium,内核是 Webkit 的分支 Blink,Windows Phone 8 系统浏览器内核是 Trident。
 

浏览器渲染过程

从图可知:浏览器从上到下解析HTML文档,碰到css样式(若是为外联,则加载css样式表),生成DOM节点树 和解析样式生成CSSOM树是同时进行的。

 

图解释:css

1.构建DOM树(DOM tree):从上到下解析HTML文档生成DOM节点树(DOM tree),也叫内容树(content tree);
2.构建CSSOM(CSS Object Model)树:加载解析样式生成CSSOM树;
3.执行JavaScript:加载并执行JavaScript代码(包括内联代码或外联JavaScript文件);
4.构建渲染树(render tree):根据DOM树和CSSOM树,生成渲染树(render tree);渲染树:按顺序展现在屏幕上的一系列矩形,这些矩形带有字体,颜色和尺寸等视觉属性。
5.布局(layout):根据渲染树将节点树的每个节点布局在屏幕上的正确位置;
6.绘制(painting):遍历渲染树绘制全部节点,为每个节点适用对应的样式,这一过程是经过UI后端模块完成;
七、合成(composite):在layout和painting以后,浏览器会将多个复合层传入GPU,进行合成工做
为了更友好的用户体验,浏览器会尽量快的展示内容,而不会等到文档全部内容到达才开始解析和构建/布局渲染树,而是每次处理一部分,并展示在屏幕上,这也是为何咱们常常能够看到页面加载的时候内容是从上到下一点一点展示的。 
 
5,6两点过程当中,若是 DOM 或 CSSOM 被修改,以上过程须要重复执行,这样才能计算出哪些像素须要在屏幕上进行从新渲染(致使重绘和回流)。

阻塞渲染:CSS 与 JavaScript

css如何阻塞渲染的?html

碰到 CSS 资源,浏览器会优先CSSOM 构建,JavaScript 执行将暂停,直至 CSSOM 就绪。因此引入顺序上,CSS 资源先于 JavaScript 资源。
渲染树的构建要求同时具备 DOM 和 CSSOM。即HTML 和 CSS 都是阻塞渲染的资源。HTML 显然是必需的,由于包括咱们但愿显示的文本在内的内容,都在 DOM 中存放,那么能够从 CSS 上想办法。
最容易想到的固然是精简 CSS 并尽快提供它。
 
  js如何阻塞渲染的?

 当浏览器遇到一个 script 标记时,DOM 构建将暂停,直至脚本完成执行前端

主流浏览器如Chrome和FireFox等都有一些优化,老是并行加载资源。好比在执行脚本时,开启另外一个进程解析剩余的文档以找出并加载其余的待下载外部资源(不改变主进程的DOM树,仅优化加载外部资源)segmentfault

 

若是脚本体积很大,下载和执行的时间就会很长,所以形成浏览器堵塞,用户会感受到浏览器“卡死”了,没有任何响应。这显然是很很差的体验,因此浏览器容许脚本异步加载,下面就是两种异步加载的语法。后端

<script src="path/to/myModule.js" defer></script>
<script src="path/to/myModule.js" async></script>

defer(下载完成延迟执行)与async(下载完成异步执行)的区别是:浏览器

defer要等到整个页面在内存中正常渲染结束(DOM 结构彻底生成,以及其余脚本执行完成),才会执行;缓存

async一旦下载完,渲染引擎就会中断渲染,执行这个脚本之后,再继续渲染。cookie

另外,若是有多个defer脚本,会按照它们在页面出现的顺序加载,而多个async脚本是不能保证加载顺序的。网络

 

重绘和回流

重绘Repaint
当页面元素样式的改变不影响元素在文档流中的位置时(例如background-color, border-color,visibility),浏览器只会将新样式赋予元素并进行重绘操做在,注意改变字体大小也会触发重绘。
 
回流Reflow
 当改变影响文档内容或者结构,或者元素位置时,回流操做就会被触发,本质仍是一个布局的过程,通常有如下几种状况:
  • DOM操做(对元素的增删改,顺序变化等);
  • 内容变化,包括表单区域内的文本改变;
  • CSS属性的更改或从新计算;
  • 增删样式表内容;
  • 修改class属性;
  • 浏览器窗口变化(滚动或缩放);
  • 伪类样式激活(:hover等)。

 

于重回和回流,浏览器自身的渲染优化策略dom

浏览器自己会尽量地减小其重绘或回流的次数,只更改必要的元素。例如一个position设置为absolute/fixed的元素的更改只会影响其自己和其子元素,而static的元素变化则会影响其以后的全部页面元素。
 
另一项优化的技术则是在JavaScript代码运行时,浏览器会缓存全部的变化,而后只经过一次pass绘制操做来应用这些更改。例以下面这段代码只会触发一次重绘和回流:
 
然而,根据咱们以前提到过的,获取某个元素的属性将会触发强制回流。好比咱们在刚才的代码中加上一句读取元素属性的操做:
结果就会有两次回流发生。所以,咱们应该尽可能合并读取元素属性的操做来优化性能。
 
强制回流
当获取一些属性时,浏览器为取得正确的值也会触发重排。这样就使得浏览器的优化失效了。
这些属性包括:offsetTop、offsetLeft、 offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeight、getComputedStyle() (currentStyle in IE)。
因此,在屡次使用这些值时应进行缓存。
 
固然也有咱们不得不触发强制回流的状况。好比说对同一个元素的margin-left属性进行两次操做——开始的时候赋值100px的距离,以后为了实现动画效果,再加上transition属性将距离改变到50px.
 
咱们先定义一个CSS类:
 
以后再对页面元素进行操做:
 
但事实上这段代码并不会像注释描述的那样运做,每条语句的操做将被缓存,只有结果会在页面上显示,因此咱们就须要手动进行一次强制回流:

 

浏览器渲染优化

合法地书写HTML和CSS,不要忘了文档编码类型。样式文件应当在 <head> 标签中,脚本文件在 <body> 结束前。
简化并优化你的CSS选择器(有些人可能CSS预处理器用习惯了历来不关注这一点)。 将嵌套层减小到最小。CSS选择器根据其优先级具备不一样的运行效率(从快到慢):
  • ID选择器: #id
  • 类选择器: .class
  • 标签选择器: div
  • 相邻选择器: a + i
  • 子元素选择器: ul > li
  • 通用选择器: *
  • 属性选择器: input[type="text"]
  • 伪类选择器: a:hover
 
浏览器中CSS选择器是从右到左进行匹配的(为何浏览器要从右到左匹配样式选择器),这也是为何越短的选择器运行越快的缘由(别提通用选择器,它会遍历全部元素):

 

  • 在你的脚本代码中,屡次访问的dom缓存下来,再去查询他们的属性。查找器尽可能简洁,减小DOM的访问
  • 将元素缓存到本地以后再进行操做,最后再添加到DOM当中,减小DOM的操做
  • 若是你使用jQuery进行DOM操做的话,最好遵循jQuery最佳实践。
  • 修改元素样式时,更改其class属性是性能最高的方法。你的选择器越有针对性越好(这一样也有助于分离页面样式和逻辑)。
  • 尽可能只对 position 为 absolute/fixed 的元素设置动画。
  • HTML文档结构层次尽可能少,最好不深于六层;
  • 少许首屏样式内联放在标签内
  • 隐藏在屏幕外,或在页面滚动时,尽可能中止动画
  • 在页面滚动时禁用 :hover 样式效果:

 

 参考文章:

前端开发者应知必会:浏览器是如何渲染网页的

浅析前端页面渲染机制

JS 必定要放在 Body 的最底部么?聊聊浏览器的渲染机制

探究 CSS 解析原理

认识 V8 引擎