浏览器渲染的原理

浏览器渲染过程:

  1. 用户输入网址(假设是个 HTML 页面,并且是第一次访问),浏览器向服务器发出请求,服务器返回 HTML 文件;
  2. 浏览器开始载入 HTML 代码,发现 <head> 标签内有一个 <link> 标签引用外部 CSS 文件;
  3. 浏览器又发出 CSS 文件的请求,服务器返回这个 CSS 文件;
  4. 浏览器继续载入 HTML 中 <body> 部分的代码,并且 CSS 文件已经拿到手了,可以开始渲染页面了;
  5. 浏览器在代码中发现一个<img> 标签引用了一张图片,向服务器发出请求。此时浏览器不会等到图片下载完,而是继续渲染后面的代码;
  6. 服务器返回图片文件,由于图片占用了一定面积,影响了后面段落的排布,因此浏览器需要回过头来重新渲染这部分代码;
  7. 浏览器发现了一个包含一行 JavaScript 代码的 <script> 标签,赶快运行它;
  8. JavaScript 脚本执行了这条语句,它命令浏览器隐藏掉代码中的某个 <div>(style.display=”none”)。由于突然少了一个元素,浏览器不得不重新渲染这部分代码;
  9. 终于等到了 </html> 的到来,浏览器泪流满面……
  10. 等等,还没完,用户点了一下界面中的“换肤”按钮,JavaScript 让浏览器换了一下 <link> 标签的 CSS 路径;
  11. 浏览器召集了在座的各位<div><span><ul><li>们,“大伙儿收拾收拾行李,咱得重新来过……”,浏览器向服务器请求了新的CSS文件,重新渲染页面。

简单来说,浏览器渲染一共有五步,
1.解析HTML标签,构建DOM树。

  • 在这个阶段,引擎开始解析html,解析出来的结果会成为一棵dom树
    dom的目的至少有2个:
    - 作为下个阶段渲染树状图的输入
    - 成为网页和脚本的交互界面。(最常用的就是getElementById等等)
    当解析器到达script标签的时候,发生下面四件事情
    1.html解析器停止解析,
    2.如果是外部脚本,就从外部网络获取脚本代码
    3.将控制权交给js引擎,执行js代码
    4.恢复html解析器的控制权
    ===由此可以得到第一个结论1====
    由于<script>标签是阻塞解析的,将脚本放在网页尾部会加速代码渲染。
    defer和async属性也能有助于加载外部脚本。
    defer使得脚本会在dom完整构建之后执行;
    async标签使得脚本只有在完全available才执行,并且是以非阻塞的方式进行的。

2.解析CSS标签,构建CSSOM树。
我们已经看到html解析器碰到脚本后会做的事情,接下来我们看下html解析器碰到样式表会发生的情况
js会阻塞解析,因为它会修改文档(document)。css不会修改文档的结构,如果这样的话,似乎看起来css样式不会阻塞浏览器html解析。但是事实上 css样式表是阻塞的。阻塞是指当cssom树建立好之后才会进行下一步的解析渲染。

  • 通过以下手段可以减轻cssom带来的影响
    将script脚本放在页面底部
    尽可能快的加载css样式表
    将样式表按照media type和media query区分,这样有助于我们将css资源标记成非阻塞渲染的资源。
    非阻塞的资源还是会被浏览器下载,只是优先级较低。
所有的样式表都会被解析成cssom对象模型(就和dom树一样展现结构),每一个页面element都会被许多css规则匹配
- 匹配顺序:origin => weight => specificity
- css origin
-作者自定义
-浏览器使用者定义
-userAgent 定义
- css weight
-normal weight
-!important weight
- css specificity (我们最应该关注的点)
注意:!important 已经被css的作者引入了浏览器,用来覆盖页面样式。
本来这个方式并不是给开发者使用的,在样式表中使用!important 会让我们忽略specificity 真正工作的原理。
- specificity 是css令人困惑的主要来源。specificity规则由(a,b,c,d)的规则决定。
-a : 值为1(当样式放在style属性中的时候),0为其它情况
-b : id在样式规则中出现的次数 eg:#slide #hello p的值就是2
-c : class,伪类,和属性在样式中出现的次数 eg:input[type=email]值就是2
-d : 标签个数(tag names)和伪类元素出现的次数
例如:
Example:
HTML
<div id=”sidebar”>
<div id=”widget” class=”class-div”>
<span class=”span-class” style=”color: red”>Hello, world!</span>
</div>
</div>

CSS
.span-class { /* Specificity (0, 0, 1, 0) */
color: green;
}

#sidebar #widget { /* Specificity (0, 2, 0, 0) */
color: orange;
}

#sidebar { /* Specificity (0, 1, 0, 0) */
color: yellow;
}

#sidebar .class-div { /* Specificity (0, 1, 1, 0) */
color: blue;
}

The inline rule, will have a specificity of (1, 0, 0, 0).
接下来的优先级是(0, 2, 0, 0);以此类推
- 使用!important 的样式覆盖都可以通过css优先级机制(比如加个样式等来提高优先级)
- 总结:
-元素样式的应用按照如下规则排列
-origin
-weight
-specificity
-order of definition
specificity只有在origin和weight一致的情况下才有效,再次就是定义的顺序
最后定义的样式会覆盖之前的样式。
- 在解析css的过程中,cssom树并不是浏览器构建的唯一数据结构,css样式匹配是件重活
为了尽可能快的加载样式,每一种最精确的匹配规则都会被加入众多哈希表中的一张 。
有针对id,class类名,标签名和一些其他不符合任何规则的哈希表。
当浏览器试图寻找哪个样式表加载到元素上的时候,它没必要查看所有的规则,而只需要查看哈希表。
这又引导我们到另一个重要的知识:我们从一个元素开始,寻找它的id,class,标签等,然后在多个字典中查找他们,
我们总是匹配**最右边**的(rightmost)的选择器,这个选择器称为**主选择器(key selector).**

这个概念开始的时候可能有些难以理解,但是它对我们如何写更快的css规则至关重要。
让我们看个例子:
HTML
<div id=”container1”>
… thousands of <a> elements here …
<a> … </a>
… thousands of <a> elements here …
</div>
<div id=”container2”>
<a class=”a-class”>...</a>
</div>
我们假如要选择container2种的a标签
This selector:
#container2 a {...}
这个选择器将会严重影响加载性能,如果从左到右读取,那就是先找到#container2然后再找a标签
,然而浏览器将会从右往左读取,它会先读取所有的a标签,然后再沿着dom往上走,直到找到#container.
这意味着这个规则会寻找所有的a,但是实际上很多a在#container1之中。
我们可以写一个更有效率的样式表:#container2 .a-class {...}。
这个特性可以在javascript或者jquery中得到很好的发挥:
eg:将$(‘#container .class-name’)改为$(‘.class-name’, ‘#container’)可以很好的性能。
-前者会先去寻找.class-name然后再沿着dom树寻找#container元素
-后者会先找到#container,然后再沿着子树寻找.class-name的元素

3.把DOM和CSSOM组合成渲染树(render tree)。

  • render树

    4.在渲染树的基础上进行布局,计算每个节点的几何结构。
    布局(layout):定位坐标和大小,是否换行,各种position, overflow, z-index属性 ……
    5.把每个节点绘制到屏幕上(painting),正式开画!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容

  • 简介浏览器可以被认为是使用最广泛的软件,本文将介绍浏览器的工 作原理,我们将看到,从你在地址栏输入google.c...
    听风阁阅读 3,268评论 0 7
  • 大家都知道万维网的应用层使用了HTTP协议,并且用浏览器作为入口访问网络上的资源。用户在使用浏览器访问一个网站时需...
    SylvanasSun阅读 2,133评论 1 12
  • 转载说明 一、介绍 浏览器可以被认为是使用最广泛的软件,本文将介绍浏览器的工作原理,我们将看到,从你在地址栏输入g...
    17碎那年阅读 2,435评论 0 22
  • 本文中浏览器特指Chrome浏览器 开始之前说说几个概念,以及在准备写这篇文章之前对浏览器的渲染机制的了解: DO...
    若邪Y阅读 3,504评论 1 10
  • 注意:下文是本人翻译之后整理的资料 什么是Table View? Table Views是一种多功能的用户界面对象...
    未知代码阅读 388评论 0 1