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% 以上的規則。
就這樣就能解決如何更快更好的查詢樣式和結合樣式構建渲染樹咯~