5-渲染树-理论剖析
DOM 树构建的同时,渲染引擎也在构建 render 树。
render 树是 HTML 文档的可视化表现,是由可视化元素按顺序展示组成的。换句话说 render 树和 DOM 树上的节点并非一一对应的,那这里有两个概念:可视化元素和非可视化元素。
非可视化元素:或是<head>
元素、或是样式display:none
的元素。 可视化元素:大多数标签,大多数样式,特别说明 visibility:hidden
也是。
而渲染树上的节点,在不用浏览器中具体的定义也不相同。Firefox中对应节点叫做 frame 而在webkit 系浏览器中节点叫做 renderer 或是 render Object。
这里着重介绍一下 renderer,主要的功能就是为后续的布局和绘制阶段提供信息计算和汇总的地方。在代码中解释为 class renderer 是 webkit中 RendererObject class 的基类,而RendererObject 具体的方法或属性如下:
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 表示为一个矩形,而这个对象中包含所需的几何信息(width、height、postion)。
但是其中的怎样生成对应 render 树节点,在不同浏览器的具体流程有所不同。
Firefox 中在 presentation 会有一个 listener ,其主要目的是监听 DOM 更新(因为 DOM 树和render 树是同时进行),一旦更新就进行使用 FrameConstructor 进行结合样式创建一个 frame 出来,该过程叫做 frame creation。
webkit 中结合样式和创建 render 的过程叫做 attachment,每一个节点都会有一个 attach 方法,每当节点插入 DOM 树是,就调用节点的 attach 方法创建 render。
清楚了具体流程是怎么样的,但是他们是如何计算每一个节点样式信息的呢?样式种类分为两种:浏览器默认样式和用户自定义样式。但计算样式上存在3个难点:
- 样式数据是一个超大的结构,存储无数的样式属性,可能造成内存问题
- 如果不优化查找样式逻辑,那么为每一个元素查找到匹配的规则会造成性能问题。
- 样式优先级问题
在 webkit 中处理的方案是,因为节点都要一个 RenderStyle 的样式对象,如果建瓯点是同级的条件下,这些对象是会被共享的。
相比 webkit 的样式对象而言,他们只是将样式存储在每一个 DOM 节点上,并没有存储在一个树形结构中,而 Firefox 则有两颗树(rule tree 和 style context tree)。rule tree 中存储所有的匹配规则,而树底层建节点的样式优先级最高,在计算节点样式信息时,计算值是可共享的,避免了同样规则的样式重复计算,节省了内存。而 style context tree 的作用就是将 DOM 节点关联规则树。具体匹配规则可以看参考文献《浏览器的工作原理:新式网络浏览器幕后揭秘》。
而上述处理方案仅仅解决了1和3这两个问题,在如何快速查找样式规则上,webkit 和 Firefox 采用 hash map 的方法。因为 inline 和 HTML 可视化属性的样式容易匹配,这方法值针对外部样式表的。当样式解析完毕,会根据选择器将 CSS 放在对应的 hash map中,具体放置规则是如果选择器是 ID,则放在 id 的哈希表中,依次类推。这样的优化方法可以排除掉 95% 以上的规则。
就这样就能解决如何更快更好的查找样式和结合样式构建渲染树咯~