浏览器的渲染原理简介

标签: 系统架构 | 发表时间:2013-06-19 23:36 | 作者:陈皓
出处:http://www.blogread.cn/it/

标签:   浏览器

   看到这个标题大家一定会想到这篇神文《 How Browsers Work》,这篇文章把浏览器的很多细节讲得很细,而且也被 翻译成了中文。为什么我还想写一篇呢?因为两个原因,

1)这篇文章太长了,阅读成本太大,不能一口气读完。

2)花了大力气读了这篇文章后可以了解很多,但似乎对工作没什么帮助。

   所以,我准备写下这篇文章来解决上述两个问题。希望你能在上班途中,或是坐马桶时就能读完,并能从中学会一些能用在工作上的东西。

浏览器工作大流程

   废话少说,先来看个图:

从上面这个图中,我们可以看到那么几个事:

1)浏览器会解析三个东西:

  • 一个是HTML/SVG/XHTML,事实上,Webkit有三个C++的类对应这三类文档。解析这三种文件会产生一个DOM Tree。

  • CSS,解析CSS会产生CSS规则树。

  • Javascript,脚本,主要是通过DOM API和CSSOM API来操作DOM Tree和CSS Rule Tree.

  •    2)解析完成后,浏览器引擎会通过DOM Tree 和 CSS Rule Tree 来构造 Rendering Tree。注意:

  • Rendering Tree 渲染树并不等同于DOM树,因为一些像Header或display:none的东西就没必要放在渲染树中了。

  • CSS 的 Rule Tree主要是为了完成匹配并把CSS Rule附加上Rendering Tree上的每个Element。也就是DOM结点。也就是所谓的Frame。

  • 然后,计算每个Frame(也就是每个Element)的位置,这又叫layout和reflow过程。

  •    3)最后通过调用操作系统Native GUI的API绘制。

    DOM解析

       HTML的DOM Tree解析如下:

    <html>
    <html>
    <head>
        <title>Web page parsing</title>
    </head>
    <body>
        <div>
            <h1>Web page parsing</h1>
            <p>This is an example Web page.</p>
        </div>
    </body>
    </html>

       上面这段HTML会解析成这样:

       下面是另一个有SVG标签的情况。

    CSS解析

       CSS的解析大概是下面这个样子(下面主要说的是Gecko也就是Firefox的玩法),假设我们有下面的HTML文档:

    <doc>
    <title>A few quotes</title>
    <para>
      Franklin said that <quote>"A penny saved is a penny earned."</quote>
    </para>
    <para>
      FDR said <quote>"We have nothing to fear but <span>fear itself.</span>"</quote>
    </para>
    </doc>

       于是DOM Tree是这个样子:

       

       然后我们的CSS文档是这样的:

     /* rule 1 */ doc { display: block; text-indent: 1em; }
    /* rule 2 */ title { display: block; font-size: 3em; }
    /* rule 3 */ para { display: block; }
    /* rule 4 */ [class="emph"] { font-style: italic; }

       于是我们的CSS Rule Tree会是这个样子:

       

       注意,图中的第4条规则出现了两次,一次是独立的,一次是在规则3的子结点。所以,我们可以知道,建立CSS Rule Tree是需要比照着DOM Tree来的。CSS匹配DOM Tree主要是从右到左解析CSS的Selector,好多人以为这个事会比较快,其实并不一定。关键还看我们的CSS的Selector怎么写了。

        注意:CSS匹配HTML元素是一个相当复杂和有性能问题的事情。所以,你就会在N多地方看到很多人都告诉你,DOM树要小,CSS尽量用id和class,千万不要过渡层叠下去,……

       通过这两个树,我们可以得到一个叫Style Context Tree,也就是下面这样(把CSS Rule结点Attach到DOM Tree上):

       

       所以,Firefox基本上来说是通过CSS 解析 生成 CSS Rule Tree,然后,通过比对DOM生成Style Context Tree,然后Firefox通过把Style Context Tree和其Render Tree(Frame Tree)关联上,就完成了。注意:Render Tree会把一些不可见的结点去除掉。而 Firefox中所谓的Frame就是一个DOM结点,不要被其名字所迷惑了

       注:Webkit不像Firefox要用两个树来干这个,Webkit也有Style对象,它直接把这个Style对象存在了相应的DOM结点上了。

    渲染

       渲染的流程基本上如下(黄色的四个步骤):

  • 计算CSS样式

  • 构建Render Tree

  • Layout - 定位坐标和大小,是否换行,各种position, overflow, z-index属性 ……

  • 正式开画

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

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

  • Repaint——屏幕的一部分要重画,比如某个CSS的背景色变了。但是元素的几何尺寸没有变。

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

  •    下面是一个打开Wikipedia时的Layout/reflow的视频(注:HTML在初始化的时候也会做一次reflow,叫 intial reflow),你可以感受一下:

       Reflow的成本比Repaint的成本高得多的多。DOM Tree里的每个结点都会有reflow方法,一个结点的reflow很有可能导致子结点,甚至父点以及同级结点的reflow。 在一些高性能的电脑上也许还没什么,但是如果reflow发生在手机上,那么这个过程是非常痛苦和耗电的

       所以,下面这些动作有很大可能会是成本比较高的。

  • 当你增加、删除、修改DOM结点时,会导致Reflow或Repaint

  • 当你移动DOM的位置,或是搞个动画的时候。

  • 当你修改CSS样式的时候。

  • 当你Resize窗口的时候(移动端没有这个问题),或是滚动的时候。

  • 当你修改网页的默认字体时。

  • 注:display:none会触发reflow,而visibility:hidden只会触发repaint,因为没有发现位置变化。

    多说两句关于滚屏的事,通常来说,如果在滚屏的时候,我们的页面上的所有的像素都会跟着滚动,那么性能上没什么问题,因为我们的显卡对于这种把全屏像素往上往下移的算法是很快。但是如果你有一个fixed的背景图,或是有些Element不跟着滚动,有些Elment是动画,那么这个滚动的动作对于浏览器来说会是相当相当痛苦的一个过程。你可以看到很多这样的网页在滚动的时候性能有多差。因为滚屏也有可能会造成reflow。

    基本上来说,reflow有如下的几个原因:

  • Initial。网页初始化的时候。

  • Incremental。一些Javascript在操作DOM Tree时。

  • Resize。其些元件的尺寸变了。

  • StyleChange。如果CSS的属性发生变化了。

  • Dirty。几个Incremental的reflow发生在同一个frame的子树上。

  • 好了,我们来看一个示例吧:

    var bstyle = document.body.style; // cache
     
    bstyle.padding = "20px"; // reflow, repaint
    bstyle.border = "10px solid red"; //  再一次的 reflow 和 repaint
     
    bstyle.color = "blue"; // repaint
    bstyle.backgroundColor = "#fad"; // repaint
     
    bstyle.fontSize = "2em"; // reflow, repaint
     
    // new DOM element - reflow, repaint
    document.body.appendChild(document.createTextNode('dude!'));

    当然,我们的浏览器是聪明的,它不会像上面那样,你每改一次样式,它就reflow或repaint一次。 一般来说,浏览器会把这样的操作积攒一批,然后做一次reflow,这又叫异步reflow或增量异步reflow。但是有些情况浏览器是不会这么做的,比如:resize窗口,改变了页面默认的字体,等。对于这些操作,浏览器会马上进行reflow。

    但是有些时候,我们的脚本会阻止浏览器这么干,比如:如果我们请求下面的一些DOM值:

  • offsetTop, offsetLeft, offsetWidth, offsetHeight

  • scrollTop/Left/Width/Height

  • clientTop/Left/Width/Height

  • IE中的 getComputedStyle(), 或 currentStyle

  • 因为,如果我们的程序需要这些值,那么浏览器需要返回最新的值,而这样一样会flush出去一些样式的改变,从而造成频繁的reflow/repaint。

    减少reflow/repaint

       下面是一些Best Practices:

        1)不要一条一条地修改DOM的样式。与其这样,还不如预先定义好css的class,然后修改DOM的className。

    // bad
    var left = 10,
    top = 10;
    el.style.left = left + "px";
    el.style.top  = top  + "px";
     
    // Good
    el.className += " theclassname";
     
    // Good
    el.style.cssText += "; left: " + left + "px; top: " + top + "px;";

        2)把DOM离线后修改。如:

  • 使用documentFragment 对象在内存里操作DOM

  • 先把DOM给display:none(有一次repaint),然后你想怎么改就怎么改。比如修改100次,然后再把他显示出来。

  • clone一个DOM结点到内存里,然后想怎么改就怎么改,改完后,和在线的那个的交换一下。

  •    3) 不要把DOM结点的属性值放在一个循环里当成循环里的变量。不然这会导致大量地读写这个结点的属性。

       4) 尽可能的修改层级比较低的DOM。当然,改变层级比较底的DOM有可能会造成大面积的reflow,但是也可能影响范围很小。

       5) 为动画的HTML元件使用fixed或absoult的position,那么修改他们的CSS是不会reflow的。

       6) 千万不要使用table布局。因为可能很小的一个小改动会造成整个table的重新布局。

       In this manner, the user agent can begin to lay out the table once the entire first row has been received. Cells in subsequent rows do not affect column widths. Any cell that has content that overflows uses the ‘overflow’ property to determine whether to clip the overflow content.

        Fixed layout, CSS 2.1 Specification

       This algorithm may be inefficient since it requires the user agent to have access to all the content in the table before determining the final layout and may demand more than one pass.

        Automatic layout, CSS 2.1 Specification

    几个工具和几篇文章

       有时候,你会也许会发现在IE下,你不知道你修改了什么东西,结果CPU一下子就上去了到100%,然后过了好几秒钟repaint/reflow才完成,这种事情以IE的年代时经常发生。所以,我们需要一些工具帮我们看看我们的代码里有没有什么不合适的东西。

  • Chrome下,Google的 SpeedTracer是个非常强悍的工作让你看看你的浏览渲染的成本有多大。其实Safari和Chrome都可以使用开发者工具里的一个Timeline的东东。

  • Firefox下这个基于Firebug的叫 Firebug Paint Events的插件也不错。

  • IE下你可以用一个叫 dynaTrace的IE扩展。

  •    最后,别忘了下面这几篇提高浏览器性能的文章:

  • Google - Web Performance Best Practices

  • Yahoo - Best Practices for Speeding Up Your Web Site

  • Steve Souders - 14 Rules for Faster-Loading Web Sites

  • 参考

  • David Baron的演讲:Fast CSS: How Browsers Lay Out Web Pages: slideshow, all slides, audio (MP3), Session page, Lanyrd page

  • How Browsers Work: http://taligarsiel.com/Projects/howbrowserswork1.htm

  • Mozilla 的 Style System Overview: https://developer.mozilla.org/en-US/docs/Style_System_Overview

  • Mozilla 的 Note of reflow: http://www-archive.mozilla.org/newlayout/doc/reflow.html

  • Rendering: repaint, reflow/relayout, restyle: http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/

  • Effective Rendering CSS: http://css-tricks.com/efficiently-rendering-css/

  • Webkit Rendering文档: http://trac.webkit.org/wiki/WebCoreRendering

  • (转载本站文章请注明作者和出处 酷壳 - CoolShell.cn ,请勿用于任何商业用途)

您可能还对下面的文章感兴趣:

  1. 浅析http协议、cookies和session机制、浏览器缓存 [2012-12-11 21:57:16]
  2. 各种浏览器审查、监听http头工具介绍 [2012-12-11 21:51:31]
  3. 浏览器的重绘[repaints]与重排[reflows] [2012-11-13 13:46:27]
  4. 抛弃 CSS Hacks 后的浏览器兼容方案 [2012-01-27 18:46:12]
  5. 以浏览器为核心的客户端软件的安全问题 [2011-08-23 13:50:42]
  6. 现代浏览器揭秘 [2011-08-23 13:26:17]
  7. Google:《关于浏览器和网络的20项须知》 [2011-08-19 23:20:25]
  8. 12款很棒的浏览器兼容性测试工具推荐 [2011-07-18 12:19:22]
  9. 浏览器多tab打开同一URL串行化的问题 [2011-07-16 20:42:28]
  10. 即时通信与浏览器多TAB通信 [2011-06-24 12:21:13]
  11. 转变代码思路:js浏览器判断方法 [2011-06-23 00:25:23]
  12. 浏览器对JavaScript代码执行的限制 [2011-06-23 00:21:34]
  13. 图说浏览器战争:火狐、微软、谷歌那些事 [2011-03-22 23:31:22]
  14. 评判浏览器API好坏的标准是什么 [2011-01-27 22:57:02]
  15. 发布本地存储开发插件-Rookie [2010-12-15 22:11:00]
  16. Flash在某些多标签浏览器中的“伪沙箱”问题 [2010-10-31 22:24:01]
  17. 五大浏览器对比测试性能 [2010-10-12 22:16:47]
  18. 用谷歌浏览器来当手机模拟器 [2010-10-07 08:27:34]
  19. 在线测试不同操作系统不同浏览器网页的显示效果 [2010-09-27 08:51:02]
  20. 各浏览器的默认CSS [2010-07-29 20:45:13]
  21. 如何高效的在多个浏览器之间同步使用的5个工具技巧 [2010-07-25 22:23:52]
  22. 关于对浏览器兼容性的一点点理解 [2010-04-25 21:58:03]
  23. 如何创建google浏览器插件 [2010-04-14 13:35:59]
  24. 浏览器缓存机制 [2010-03-08 23:12:36]
  25. PHP强制浏览器不缓存的方法 [2009-12-24 23:54:39]
  26. IE8开发人员工具如何嵌入浏览器 [2009-12-07 11:27:51]
  27. js不同浏览器检测 [2009-11-13 18:38:20]
  28. 控制浏览器是否缓存网页状态 [2009-11-10 12:36:46]
  29. 随身携带的设计 [2009-11-09 13:36:16]
  30. IE5至IE7读取不了4095行以后的CSS [2009-11-08 21:51:29]
  31. CSS让你的IE浏览器崩溃 [2009-11-08 21:50:01]
  32. 浏览器的结构 [2009-10-29 13:52:37]
  33. javascript 在各个浏览器中的超时时间 [2009-10-14 13:33:51]

相关 [浏览器 渲染 原理] 推荐:

“浏览器渲染原理”PPT

- zhibin - 宅居
这是今天一次内部分享的PPT,其中内容主要来自于Winter大大分享的相关材料,和How Browser Work这一文的一些内容. 由于内部分享是以讲为主,因此PPT并不包含所有内容,仅仅是一个摘要的形式,另有以下几点:. 由于是在MAC下制作的,在Windows下播放可能由于字体等原因,造成排版错乱,请自行脑补或调整.

浏览器的渲染原理简介

- - IT技术博客大学习
   看到这个标题大家一定会想到这篇神文《 How Browsers Work》,这篇文章把浏览器的很多细节讲得很细,而且也被 翻译成了中文. 1)这篇文章太长了,阅读成本太大,不能一口气读完. 2)花了大力气读了这篇文章后可以了解很多,但似乎对工作没什么帮助.    所以,我准备写下这篇文章来解决上述两个问题.

浏览器如何渲染文本

- old9 - jjgod / blog
浏览器是我们最常用的软件之一,文本又是网页中最主要的元素,在浏览器显示文本的过程中有许多有趣的细节,值得展开来讲讲,或许能减少一些误解. 这是一个比较粗略的,概括性的介绍,尽可能不涉及过多的技术细节和具体实现,而立足于给 Web 开发者和设计师提供一些正确的概念. 下面的介绍主要根据我对 WebKit 和 Gecko (Firefox) 的印象来谈,其他的浏览器也大致相同,如有阙漏之处欢迎指出.

浏览器加载和渲染html的顺序-css渲染效率的探究

- - CSDN博客互联网推荐文章
1.浏览器加载和渲染html的顺序. 1、IE下载的顺序是从上到下,渲染的顺序也是从上到下,下载和渲染是同时进行的. 2、在渲染到页面的某一部分时,其上面的所有部分都已经下载完成(并不是说所有相关联的元素都已经下载完). 3、如果遇到语义解释性的标签嵌入文件(JS脚本,CSS样式),那么此时IE的下载过程会启用单独连接进行下载.

拾人牙慧:不同浏览器如何渲染不同border-style值

- Lee - 张鑫旭-鑫空间-鑫生活
本文地址:http://www.zhangxinxu.com/wordpress/?p=1972. 本文的一些测试结果不是出自我手,来自:How Do Browsers Render the Different CSS Border Style Values?. 满脑子都是国庆假期,要是原文翻译根本没有这个精气神.

浏览器是怎样工作的:渲染引擎,HTML解析(连载二)

- - 携程UED
渲染引擎的职责是……渲染,也就是把请求的内容显示到浏览器屏幕上. 默认情况下渲染引擎可以显示HTML,XML文档以及图片. 通过插件(浏览器扩展)它可以显示其它类型文档. 比如使用PDF viewer插件显示PDF文件. 我们会在一个专门的章节讨论插件与扩展. 在这一节我们将专注渲染引擎的主要用途——显示用CSS格式化的HTML与图片.

[转]手机浏览器工作原理

- - 小鸥的博客
现在电脑上的浏览器越来越多,出现了几大内核的浏览器纷争的局面. (小知识)几种常见的浏览器内核简介及优缺点:. Trident:Windows 下的 IE 浏览器使用的内核代号. 除 IE 外,众多的 IE Shell(如 Maxthon)都使用这个内核. 70%的占有率,几乎所有的互联网页面都要参照这个内核进行页面优化所以页面显示效果最好.

尝试解析下 Epub.js:一个在浏览器上渲染 Epub 图书的工具

- - IT瘾-dev
一直在看 Epub 类型的图书, 很好奇一个 Epub 解析器是如果工作的. 碰巧看到了 Epub.js, 体验了一下还可以. 本文会先介绍下 EPUB 格式,再来分析 Epubjs 的实现. 我前端经验仅限于了解常见标签含义,可能会有各种错误恳请斧正. EPub是一个自由的开放标准,属于一种可以“自动重新排版”的内容;也就是文字内容可以根据阅读设备的特性,以最适于阅读的方式显示.

web基础-web工作原理,http协议,浏览器缓存

- - 浏览器 - 互联网 - ITeye博客
4,cookie和session. 平时用浏览器,输入网址后回车,页面响应我们想要浏览的内容,简单操作的背后蕴涵了什么原理. 当输入url回车后,客户端(浏览器)会去请求DNS服务器,通过DNS获取域名对应的IP地址,然后通过这个地址找到对应的服务器,要求建立TCP连接,建立连接,客户端发送httpRequest(请求包)后,服务器接收并开始处理请求,调用自身服务,返回httpResponse(响应包),客户端收到响应包后开始渲染body主体,等到全部接收,断开与该服务器端的TCP连接.