浏览器在构造DOM树的同时也在构造着另一棵树-Render Tree,与DOM树相对应暂且叫它Render树吧,我们知道DOM树为javascript提供了一些列的访问接口(DOM API),但这棵树是不对外的。它的主要作用就是把HTML按照一定的布局与样式显示出来,用到了CSS的相关知识。从MVC的角度来说,可以将render树看成是V,dom树看成是M,C则是具体的调度者,比HTMLDocumentParser等。

  新概念Render树

  每一个Render树的节点称之为renderer或者render object,查看WEBKIT的源代码我们可以发现Renderer一个基础的类定义,这个类是所有renderer对象的基类。

class RenderObject{
virtual void layout();
virtual void paint(PaintInfo);
virtual void rect repaintRect();
Node* node; //the DOM node
RenderStyle* style; // the computed style
RenderLayer* containgLayer; //the containing z-index layer
}

  从中我们可以发现renderer包含了一个dom对象以及为其计算好的样式规则,提供了布局以及显示方法。具体效果图如下:(firefox的Frames对应renderers,content对应dom)

  

  具体显示的时候,每一个renderer体现了一个矩形区块的东西,即我们常说的CSS盒子模型的概念,它本身包含了一些几何学相关的属性,如 宽度width,高度height,位置position等。每一个renderer还有一个很重要的属性,就是如何显示它,display。我们知道元 素的display有很多种,常见的就有none,inline,block,inline-block....,不同的display它们之间到底有啥 不同呢?我们看一下代码:

  

RenderObject* RenderObject::createObject(Node* node, RenderStyle* style)
{
Document* doc = node->document();
RenderArena* arena = doc->renderArena();
...
RenderObject* o = 0; switch (style->display()) {
case NONE:
break;
case INLINE:
o = new (arena) RenderInline(node);
break;
case BLOCK:
o = new (arena) RenderBlock(node);
break;
case INLINE_BLOCK:
o = new (arena) RenderBlock(node);
break;
case LIST_ITEM:
o = new (arena) RenderListItem(node);
break;
...
} return o;
}

  更详细的可见WEBKIT源码了,上面只是列出了片段。

  DOM树与Render树

  可以这么说,没有DOM树就没有Render树,但是它们之间可不是简单的一对一的关系。我们已经知道了 render树是用于显示的,那不可见的元素当然不会在这棵树中出现了,譬如<header>,您还能想到哪些呢?除此之外,diplay等 于none的也不会被显示在这棵树里头,但是visibility等于hidden的元素是会显示在这棵树里头的,可以自己想一下为什么。说了这么多 render树,我们还没见一下它的真容呢,它到底会是个什么模样呢?我们看一下图。

  与DOM对象类型很丰富啊,什么head,title,div,而Render树相对来说就比较单一了,毕竟它的职责就是为了以后的显示渲染用 嘛。从上图我们还可以看出,有些DOM元素没有对应的renderer,而有些DOM元素却对应了好几个renderer,对应多个renderer的情 况是普遍存在的,就是为了解决一个renderer描述不清楚如何显示出来的问题,譬如select元素,我们就需要三个renderer,one for the display area, one for the drop down list box and one for the button。

  上图中还有一种关系未可看出,即renderer与dom元素的位置也可能是不一样的。说的就是那些添加了float:ETC或者position:absolute的元素,因为它们脱离了正常的文档流顺序,构造Render树的时候会针对它们实际的位置进行构造。

  DOM树可能会被我们随时更新,不仅限于解析阶段,譬如$elment.append啦或 者$elment.addClass啦,我们看到页面立即进行了显示刷新,浏览器针对这种情况进行了相关处理。Dom树的根节点我们知道是 doument,Render树的根节点不同浏览器可能有不同的叫法,webkit叫它RenderView,firefox叫它ViewPortFrame。

  CSS的解析

  CSS用到的所有词汇定义规范如下:

comment     \/\*[^*]*\*+([^/*][^*]*\*+)*\/
num     [0-9]+|[0-9]*"."[0-9]+
nonascii    [\200-\377]
nmstart     [_a-z]|{nonascii}|{escape}
nmchar      [_a-z0-9-]|{nonascii}|{escape}
name        {nmchar}+
ident       {nmstart}{nmchar}*

  注:ident代表样式中的class,name代表样式中的id。

  CSS用到的语法BNF格式的定义如下:

ruleset
  : selector [ ',' S* selector ]*
    '{' S* declaration [ ';' S* declaration ]* '}' S*
  ;
selector
  : simple_selector [ combinator selector | S+ [ combinator selector ] ]
  ;
simple_selector
  : element_name [ HASH | class | attrib | pseudo ]*
  | [ HASH | class | attrib | pseudo ]+
  ;
class
  : '.' IDENT
  ;
element_name
  : IDENT | '*'
  ;
attrib
  : '[' S* IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S*
    [ IDENT | STRING ] S* ] ']'
  ;
pseudo
  : ':' [ IDENT | FUNCTION S* [IDENT S*] ')' ]
  ;

  样式计算

  每个HTML元素上,我们可能定义了很多不同类型的样式,如字体啦,颜色啦,布局啦等等。即使元素上不被我们定义样式,浏览器或者用户个性设置也会为它默认创造一些样式。

  样式计算一项极其复杂的过程,我们定义样式的时候可以采用类似类的定义方式为一批元素设置样式,但是解析构造renderer的时候,浏览器是 为每一个构造样式定义的。我们可能定义了极其多的样式而且有各种不同的规则,那找到元素匹配的样式规则是挺困难的。浏览器有多重算法错误来实现计算工作, 具体就不细分析了,一个元素最终经过计算可能匹配到了很多条样式规则,他们之间存在一定的优先顺序,从低到高有:

  1.   浏览器默认样式
  2.   用户个性化浏览器设置
  3.   HTML开发者定义的一般样式
  4.   HTML开发者定义的!important样式
  5.   用户个性化浏览器设置!important样式

  更详细的优先计算公式

  • count 1 if the declaration is from is a 'style' attribute rather than a rule with a selector, 0 otherwise (= a)
  • count the number of ID attributes in the selector (= b)
  • count the number of other attributes and pseudo-classes in the selector (= c)
  • count the number of element names and pseudo-elements in the selector (= d)

  具体可见http://www.w3.org/TR/CSS2/cascade.html#specificity

  举例说明

*             {}  /* a=0 b=0 c=0 d=0 -> specificity = 0,0,0,0 */
li {} /* a=0 b=0 c=0 d=1 -> specificity = 0,0,0,1 */
li:first-line {} /* a=0 b=0 c=0 d=2 -> specificity = 0,0,0,2 */
ul li {} /* a=0 b=0 c=0 d=2 -> specificity = 0,0,0,2 */
ul ol+li {} /* a=0 b=0 c=0 d=3 -> specificity = 0,0,0,3 */
h1 + *[rel=up]{} /* a=0 b=0 c=1 d=1 -> specificity = 0,0,1,1 */
ul ol li.red {} /* a=0 b=0 c=1 d=3 -> specificity = 0,0,1,3 */
li.red.level {} /* a=0 b=0 c=2 d=1 -> specificity = 0,0,2,1 */
#x34y {} /* a=0 b=1 c=0 d=0 -> specificity = 0,1,0,0 */
style="" /* a=1 b=0 c=0 d=0 -> specificity = 1,0,0,0 */ 布局
  上面确定了renderer的样式规则后,然后就是重要的显示因素布局了。当renderer构造出来并添加到render树上之后,它并没有位置跟大小信息,为它确定这些信息的过程,我们就称之为布局。HTML采用了一种流式布局的布局模型,从上到下,从左到右顺序布局,布局的起点是从render树的根节点开始的,对应dom树的document节点,其初始位置为0,0,详细的布局过程为: 每个renderer的宽度由父节点的renderer确定。 父节点遍历子节点,确定子节点的位置(x,y),调用子节点的layout方法确定其高度。 父节点根据子节点的height,margin,padding确定自身的自身的高度。
  为了避免因为局部小范围的DOM修改或者样式改变引起整个页面整体的布局重新构造,浏览器采用了一种dirty bit system的技术,使其尽可能的只改变元素本身或者包含的子元素的布局。当然有些情况无可避免的要重新构造整个页面的布局,如适合于整体的样式的改变影响了所有renderer,如body{font-size:111px} 字体大小发生了改变,还有一种情况就是浏览器窗口进行了调整,resize。
  对于界面设计来说,一个页面最难搞的应该就是排版布局了,内容也比较多,我们下文进行说明 From:http://www.cnblogs.com/luluping/archive/2013/04/05/3000460.html

render tree与css解析的更多相关文章

  1. 渲染树render tree

    CSSOM树和DOM树连接在一起形成一个render tree,渲染树用来计算可见元素的布局并且作为将像素渲染到屏幕上的过程的输入. DOM树和CSSOM树连接在一起形成render tree . r ...

  2. 浏览器-05 HTML和CSS解析1

    一个浏览器内核几个主要部分,HTML/CSS解析器,网络处理,JavaScript引擎,2D/3D图形引擎,多媒体支持等; HTML 解析和 DOM 网页基本结构 一个网页(Page),每个Page都 ...

  3. IE6常见CSS解析Bug及hack

    IE6常见CSS兼容问题总结 1)图片间隙 A)div中的图片间隙(该bug出现在IE6及更低版本中) 描述:在div中插入图片时,图片会将div下方撑大三像素. hack1:将</div> ...

  4. ASP.NET重写Render 加载CSS样式文件和JS文件(切换CSS换皮肤)

    网页换皮肤的方式有很多种,最简单的通常就是切换页面CSS,而CSS通常写在外部CSS文件里.那么切换CSS其实就是更换html里的link href路径.我在网上搜索了下. 一般有两种方式: 1.页面 ...

  5. css解析规则

    1.因为css对空格不敏感,因此在每个样式后都要加一个分号,不然会把写在后面的样式当成一个整体来解析,直到遇到分号为止. 2.当遇见不认识的属性或值时,将忽略这个属性,继续解析后面的属性. 3.对于复 ...

  6. 浏览器-06 HTML和CSS解析2

    选择器 其实现由CSSSelector类来完成: CSSSelector的作用是储存从解析器生成的结果信息; 这里匹配指的是当需要为每个DOM中的节点计算样式时,WebKit需要根据当前的节点信息来从 ...

  7. nginx配置 send_timeout 引发的js、css解析失败问题

    错误情况是web界面排版错误,js.css文件加载失败,通过调试器查看js和css文件路径都是对的,而且可访问. 业务使用的是 nginx+php+mysql+redis的架构 解决办法: 查了很多资 ...

  8. 网站怎么布局能解决不同浏览器对CSS解析的差异,使用css reset

    很多地方都提到过CSS Reset这个概念,而且细心的朋友会发现,许多大网站的CSS文件中也含有CSS Reset内容. CSS Reset是什么? 在HTML标签在浏览器里有默认的样式,例如 p 标 ...

  9. IE6常见CSS解析Bug和hack

    第一:图片间隙 a:div中的图片间隙: 描述:在div中插入图片时,图片会将div下方撑大3像素 hack1:将<div>和<img>写在一行 hack2:将<img& ...

随机推荐

  1. 第三次ScrumMeeting

    每个人的工作(有Issue的内容和链接):昨天已完成的工作,今天计划完成的工作:工作中遇到的困难. --by 张华杰 团队成员 昨日完成任务 明日要完成的任务 易子沐 搭建主页框架 issue14 前 ...

  2. _Meta 部分用法

    model.UserInfo._meta.app_label #获取该类所在app的app名称 model.UserInfo._meta.model_name #获取该类对应表名(字符串类型) mod ...

  3. HTML实用案例(1)—— 左侧菜单,右侧内容的布局(带左侧菜单点击隐藏显示效果)

    效果图 代码部分 <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" ...

  4. UVA 11291 Smeech

    [来源]https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...

  5. UVALive - 3490 Generator (AC自动机+高斯消元dp)

    初始有一个空串s,从前n个大写字母中不断随机取出一个字母添加到s的结尾,出现模式串t时停止,求停止时s的长度期望. 这道题解法不唯一,比较无脑的方法是对模式串t建一个单串AC自动机,设u为自动机上的一 ...

  6. Redis底层探秘(四):整数集合及压缩列表

    整数集合 整数集合(intset)是集合键的底层实现之一,当一个集合只包含 整数值元素,并且这个集合的元素数量不多时,Redis就会使用郑书记和作为集合键的底层实现. 整数集合的实现 整数集合是red ...

  7. VC2005中将Picture控件显示图片保存为BMP,JPG等格式

    1.在stdafx.h头文件中加入 #include <atlimage.h> 2.保存图片 方法一:   HBITMAP hBitmap = NULL; //创建位图段 BITMAPIN ...

  8. PIX v2版本中Query 失败时, ERR段的构造

    在ITI-9中描述PIX query事务的几个TestCase场景.其中有些是对于Query失败的描述. ERR 段包含Error location, Error code, Error code t ...

  9. djangocms安装使用指南

    ubuntu 14.04 virtualenv venv --python=python3 . venv/bin/activate sudo apt-get upgradesudo apt-get i ...

  10. Oracle 常用语句SQL

    查询Oracle 用户下面的所有表,表注释,行数 select t.TABLE_NAME, s.comments,t.NUM_ROWS  from user_tables t, user_tab_co ...