DOM 樹構建的同時,渲染引擎也在構建 render 樹。javascript
render 樹是 HTML 文檔的可視化表現,是由可視化元素按順序展現組成的。換句話說 render 樹和 DOM 樹上的節點並不是一一對應的,那這裏有兩個概念:可視化元素和非可視化元素。java
非可視化元素:或是<head>
元素、或是樣式display:none
的元素。 可視化元素:大多數標籤,大多數樣式,特別說明 visibility:hidden
也是。node
而渲染樹上的節點,在不用瀏覽器中具體的定義也不相同。Firefox中對應節點叫作 frame 而在webkit 系瀏覽器中節點叫作 renderer 或是 render Object。web
這裏着重介紹一下 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。post
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% 以上的規則。
就這樣就能解決如何更快更好的查找樣式和結合樣式構建渲染樹咯~