浏览器渲染过程

来源:互联网 发布:电脑无法识别9008端口 编辑:程序博客网 时间:2024/05/29 18:02

为什么要了解浏览器加载、解析、渲染这个过程?
了解浏览器如何进行加载,我们可以在引用外部样式文件,外部js时,将他们放到合适的位置,使浏览器以最快的速度将文件加载完毕。
了解浏览器如何进行解析,我们可以在构建DOM结构,组织css选择器时,选择最优的写法,提高浏览器的解析速率。
了解浏览器如何进行渲染,明白渲染的过程,我们在设置元素属性,编写js文件时,可以减少”重绘“”重新布局“的消耗。
这三个过程在实际进行的时候又不是完全独立,而是会有交叉。会造成一边加载,一边解析,一边渲染的工作现象。

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文件和图片,浏览器会另外发出一个请求,来获取css文件和相应的图片,这个请求是异步的,并不会影响html文件。
但是如果遇到javascript文件,html文件会挂起渲染的线程,等待javascript加载完毕后,html文件再继续渲染。

为什么html需要等待javascript呢?因为javascript可能会修改DOM,导致后续的html资源白白加载,所以html必须等待javascript文件加载完毕后,再继续渲染。这也就是为什么javascript文件要写在底部body标签前的原因。

html的渲染过程就是将html代码按照深度优先遍历来生成DOM树。
css文件下载完后也会进行渲染,生成相应的CSSOM。
当所有的css文件下载完且所有的CSSOM构建结束后,就会和DOM一起生成Render Tree。
接下来,浏览器就会进入Layout环节,将所有的节点位置计算出来。
最后,通过Painting环节将所有的节点内容呈现到屏幕上。

渲染
渲染的流程基本上如下(黄色的四个步骤):
计算 CSS 样式
构建 Render Tree
Layout – 定位坐标和大小,是否换行,各种 position, overflow, z-index 属性 ……
正式开画
这里写图片描述

上图流程中有很多连接线,这表示了 Javascript 动态修改了 DOM 属性或是 CSS 属性会导致重新 Layout,有些改变不会,就是那些指到天上的箭头,比如,修改后的 CSS rule 没有被匹配到

这里重要要说两个概念,一个是 Reflow,另一个是 Repaint。这两个不是一回事。

Repaint——(重绘)是在一个元素的外观被改变,但没有改变布局的情况下发生。如果只是改变某个元素的背景色、文字颜色、边框颜色等等不影响它周围或内部布局的属性,将只会引起浏览器repaint。

Reflow——(回流):浏览器发现某个部分发生了点变化影响了布局,需要倒回去重新渲染,这个回退的过程就叫回流。意味着元件的几何尺寸变了,我们需要重新验证并计算 Render Tree。是 Render Tree 的一部分或全部发生了变化。这就是 Reflow,或是 Layout。(HTML 使用的是 flow based layout,也就是流式布局,所以,如果某元件的几何尺寸发生了变化,需要重新布局,也就叫 reflow)。reflow 会从 <html> 这个 root frame 开始递归往下,依次计算所有的结点几何尺寸和位置,在 reflow 过程中,可能会增加一些 frame,比如一个文本字符串必需被包装起来。

display:none 会触发 reflow(元素原来的位置不保留),而 visibility:hidden 只会触发 repaint(仅仅为视觉上的不可见,原来的位置仍然保留着),因为没有发现位置变化。

重排 reflow
当改变影响到文本内容、结构或元素位置时,就会发生重排。通常有以下事件触发:
网页初始化时
DOM操作(元素添加、删除、修改、元素顺序变化)
内容变化,包括表单域内文本改变
CSS属性的计算或改变
添加或删除样式表
更改“类”属性
浏览器窗口的缩放、滚动等
伪类激活(例如:hover悬停)

构建渲染树的过程,也就是原来DOM树的可视化表示,构建这棵树是为了以正确的顺序绘制文档内容。

渲染树和DOM树的关系,不可见的dom元素(<head>…</head> display=none)不会被插入渲染树中。还有像一些节点的位置为绝对或浮动定位(需要css知识理解),这些节点会在文本流之外,因此会在两棵树上的不同位置,渲染树标识出真实的位置,并用一个占位结构标识出他们原来的位置。

渲染最大的一个困难就是为每一个dom节点计算符合他的最终样式。
为每一个元素查找到匹配的样式规则,需要遍历整个规则表。

浏览器解析css选择器

浏览器按“从右向左”读取。意味着在选择器 ul > li a[title=”home”] 中,首先被解析的是a[title=”home”]

#test p{ color:#999999}
正解:遍历是自右向左,也就是先查询到p元素,再找到上一级id为test的元素。

ID选择符最高效,通配选择符效率最低

#main-navigation {   }      /* ID (最快) */body.home #page-wrap {   }  /* ID */.main-navigation {   }      /* Class */ul li a.current {   }       /* Class *ul {   }                    /* Tag */ul li a {  }                /* Tag */* {   }                     /* 通配 (最慢) */
#main-nav > li {   }  /* 比你想象的要慢 */不是先找id,而是从li元素找起

不要用标签修饰id选择器
ul#main-navigation { }//ID是唯一的,所以它们不需要和标签在一起。这样做反而会降低效率。

后代选择器是最糟糕的 html body ul li a { }

0 0
原创粉丝点击