摘要:書接上文瀏覽器內核之解釋器和模型本文剖析的解釋器和樣式布局。根據生成解釋器類。而后將解釋后的信息設置到元素的屬性的樣式中,然后設置標記表明該元素需要重新計算樣式,并觸發重新計算布局。
微信公眾號:愛寫bugger的阿拉斯加前言
如有問題或建議,請后臺留言,我會盡力解決你的問題。
此文章是我最近在看的【WebKit 技術內幕】一書的一些理解和做的筆記。
而【WebKit 技術內幕】是基于 WebKit 的 Chromium 項目的講解。
書接上文 瀏覽器內核之 HTML 解釋器和 DOM 模型
本文剖析 WebKit 的 CSS 解釋器和樣式布局。
從整個網頁的加載和渲染過程來看,CSS 解釋器和規則匹配處于 DOM 樹建立之后,RenderObject 樹建立之前,CSS 解釋器解釋后的結果會保存起來,然后 RenderObject 樹基于該結果來進行規范匹配和布局計算。當網頁有用戶交互或者動畫等動作的時候,通過 CSSDOM 等技術,JavaScript 代碼同樣可以非常方便地修改 CSS 代碼,WebKit 此時需要重新解釋樣式并重復以上這一過程。
1. CSS 基本功能 1.1.1 簡介CSS 的全稱是 Cascading Style Sheet,中文名是級聯樣式表,主要用來控制網頁的顯示風格。
1.1.2 樣式規則圖 6-1 描述了一個典型的 CSS 規則結構。一個規則包括兩個部分——規則關和規則體。規則頭由一個或者多個選擇器組成;規則體則由一個或者多個樣式聲明組成,每個樣式聲明由樣式名和樣式值構成,表示這個規則對哪些樣式進行了規定和設置。
當 HTML 中的某個元素經過后面的匹配算法使用了這條規則,那么將這些樣式設置成該元素的樣式,除非有更高優先級的規則匹配上該元素。
1.1.3 選擇器CSS 的選擇器是一級模式,用來匹配相應的 HTML 元素。當選擇器匹配相應元素的時候,該選擇器包含的各種樣式值就會作用于匹配的元素上。通過選擇器,CSS 能夠精準地控制 HTML 頁面中的任意一個或者多個元素的樣式屬性。
具體的,這里不做介紹,請查閱 CSS 規范。
1.1.4 框模型框模型(Box model,或稱箱子模型)就是我們常說的盒子模型,是CSS 標準中引入來表示 HTML 標簽元素的布局結構。一個框模型大致包括四個部分:外邊距(Margin)、邊框(Border)、內邊距(Padding)和內容(Content)。
1.4.5 包含塊(Containing Block)模型當 WebKit 計算元素的箱子的位置和大小時,WebKit 需要計算該元素和另外一個矩形區域的相對位置,這個矩形區域稱為該元素的包含塊。上面介紹的框模型就是在包含塊內計算和確定各個元素的,包含塊的具體定義如下:
根元素的包含塊稱為初始包含塊,通常它的大小就是可視區域(Viewport)的大小。
對于其他位置屬性設置為 “static” 或者 “relative” 的元素,它的包含塊就是最近祖先的箱子模型中的內容區域(Content)。
如果元素的位置屬性為 “fixed” ,那么該元素的包含快脫離 HTML 文檔,因定在可視區域的某個特定位置。
如果元素的位置屬性為 “absolute” ,那么該元素的包含塊由最近的含有屬性 “absolute”、“relative”、或者 “fixed” 的祖先決定,具體規則如下:如果一個元素具有 “inline” 屬性,那么元素的包含塊是該祖先的第一個和最近一個 inline 框的內邊距的區域;否則,包含塊則是該祖先的內邊距所包圍的區域。
1.1.6 CSS 樣式屬性CSS 標準中定義了各式各樣的樣式屬性,用來描述元素的顯示效果。
這些屬性大致分成以下類型:
背景:如背景顏色和背景圖片等。
文本:設置文本縮進,對齊。單詞間隔。字母間隔。字符轉換、裝飾和空白字符等。
字體:設置字體屬性,可以是內嵌的,也可以是自定義字體的方式,另外還可以設置加粗、變形等屬性。
列表:設置列表類型,可以以字母、希臘字母、數字等方式編號列表。
表格:通過設置邊框來達到顯示表格的視覺效果的目的。設置是否把表格邊框合并為單一的邊框,設置分隔單元格邊框的距離,設置表格標題的位置,設置是否顯示表格中的空單元格,設置顯示單元、行和列的算法等。
定位:CSS 提供元素的相對、絕對定位和浮動定位。
1.1.7 CSSOM(CSS Object Model)CSSOM 稱為 CSS 對象模型。它思想是在 DOM 中的一些節點接口中,加入獲取和操作 CSS 屬性或者接口的 JavaScript 接口,因而 JavaScript 可以動態操作 CSS 樣式。DOM 提供了接口讓 JavaScript 修改 HTML 文檔,同理,CSSOM 提供了接口讓 JavaScript 獲得和修改 CSS 代碼設置的樣式信息。
對于內部和外部樣式表,CSSOM 定義了樣式表的接口,稱為 “CSSStyleSheet”, 這是一個可以在 JavaScript 代碼中訪問的接口。借助這個接口,開發者可以在 JavaScript 中獲取樣式表的各種信息,例如 CSS 的 “href”、樣式表類型 “type”、規則信息 “cssRules” 等,甚至可以獲取樣式表中的 CSS 規則列表。這個接口同 DOM 中的 “Script” 節點或者 “Link” 節點不一樣,它是 CSSOM 定義的新接口。開發者可以通過 document.styleSheets 查看當前網頁中包含的所有 CSS 樣式表,這是因為 CSSOM 對 DOM 中的 Document 接口進行了擴展,下面是新加入的屬性:
W3C 還定義了另外一個規范是 CSSDOM View,它的基本含義是增加一些新的屬性到 Window、Document、Element、HTMLElement 和 MouseEvent 等接口,這些 CSS 的屬性能夠讓 JavaScript 獲取視圖信息,用于表示跟視圖相關的特征,例如窗口大小,網頁滾動位移,元素的框位置、鼠標事件的坐標等信息。下面是以 CSSDOM View 對 Window 的擴展:
1.2 CSS 解釋器和規則匹配 1.2.1 樣式的 WebKit 表示類對于 CSS 樣式表,不管是內嵌還是外部文檔,WebKit 都使用 CSSStyleSheet 類來表示。圖 6-5 描述了 WebKit 內部是如何表示 CSS 文檔的。
一切的起源都是從 DOM 的 Document 類開始。
DoucmentStyleSheetCollection 類,該類包含了所在 CSS 樣式表
WebKit的內部表示類 CSSStyleSheet,它包含 CSS 的 href 、類型、內容等信息。
CSS 的內容就是樣式信息 StyleSheetContent,包含了一個樣式規則 (StyleRuleBase)列表。樣式規則被 用在 CSS 的解釋器的工作過程中。
下面部分 WebKit 主要是將解釋之后的規則組織起來,用于為 DOM 中的元素匹配相應的規則,從而應用規則中的屬性值序列。這一過程的主要負責者是 StyleSheetResolver 類,它屬于 Document 類,并包含了一個 DocumentRuleSets 類用來表示多個規則集合(RuleSet)。每個規則集合就是將之前解釋之后的結果合并起來,并進行分類,例如 id 類規則,標簽類規則等。至于為什么是多個規則集合,是因為這些規則集合可能源自于默認的規則集合,或者網頁自定義的規則集合等。
1.2.2 解釋過程CSS 解釋過程是指從 CSS 字符串經過 CSS 解釋器處理后變成渲染引擎內部規則的表示過程。
在 WebKit 中,過程如 6-8 所示。
這一過程是基本思想是由 CSSParser 類負責。CSSParser 類其實也是橋接類,實際的解釋工作是由 CSSGrammer.y.in 來完成。CSSGrammer.y.in 是Bison 的輸入文件,Bioson 是一個生成解釋器的工具。Bison 根據 CSSGrammer.y.in 生成 CSS 解釋器——CSSGrammer 類。當然 CSSGrammer 類需要調用 CSSParser類來處理解釋結果,例如需要使用 CSSParser 類創建選擇器對象、屬性、規則等。
在解釋網頁中自定義的 CSS 樣式之前,實際上 WebKit 渲染引擎會為每個網頁設置一個默認的樣式,這決定了網頁所沒有設置的元素屬性及其屬性默認值和將要顯示的效果。一般來講,不同的 WebKit 移植可以設置不同的默認樣式。下面是 Chrome 瀏覽器使用的默認樣式,這些樣式決定了默認的網頁顯示效果。
1.2.4 樣式規則匹配樣式規則建立完成之后,WebKit 保存規則結果在 DocumentRuleSets 對象類中。當 DOM 的節點建立之后,WebKit 會為其中的一些節點(只限于可視節點)選擇合適的樣式信息。這些工作都是由 StyleResolver 來負責。當然,實際的匹配工作還是在 DocumentRuleSets 類中完成的。
圖 6-9 描述了參與樣式規則匹配的 WebKit 主要相關類。基本思路是使用 StyleResolver 類來為 DOM 的元素節點匹配樣式。StyleResolver 類根據元素的信息,例如標簽名、類別等,從樣式規則中查找最匹配的規則,然后將樣式信息保存到新建的 RenderStyle 對象中。最后,最后這些 RenderStyle 對象被 RenderObject 類所管理和使用。
規則的匹配則是由 ElementRuleCollector 類來計算并獲得,它根據元素的屬性等,并從 DocumentRuleSets 類中獲取規則集合,依次按照 ID、類別、標簽等選擇器信息逐次匹配獲得元素的樣式。
首先,當 WebKit 需要為 HTML 元素創建 RenderObject 類的時候,首先 StyleResolver 類負責獲取樣式信息,并返回 RenderStyle 對象,RenderStyle 對象包含了匹配完的結果樣式結果。
其次,根據實際需求,每個元素可能需要匹配不同來源的規則,依次是用戶代理(瀏覽器)規則集合、用戶規則集合和 HTML 網頁中包含的自定義規則集合。這三個規則的匹配方式是類似的。這里是以自定義規則匹配為例加以說明的。
再次,對于自定義規則集合,它先查找 ID 規則,檢查有無匹配的規則,之后依次檢查類型規則,標簽規則等,如果某個規則匹配上該元素,WebKit 把這些規則保存到匹配結果中。
最后,WebKit 對這些規則進行排序。對于該元素需要的樣式屬性,WebKit 選擇從高優先級規則中選取,并將樣式屬性值返回。
1.2.5 JavaScript 設置樣式CSSDOM 定義了 JavaScript 訪問樣式的能力和方式。使用 CSSDOM 接口來更改屬性值的過程,在 WebKit 中,這需要 JavaScript 引擎和渲染引擎協同完成。
大致的過程是,JavaScript 引擎調用設置屬性值的公共處理函數,然后該函數調用屬性值解析函數,在這個例子中則是 CSS 的 JavaScript 綁定函數。而后 WebKit 將解釋后的信息設置到元素的 “style” 屬性的樣式 “webkitTransform” 中,然后設置標記表明該元素需要重新計算樣式,并觸發重新計算布局。最后是 WebKit 的重新繪圖,圖 6-12 描述了其中的主要過程。
1.3 WebKit 布局 1.3.1 基礎當 WebKit 創建 RenderObject 對象之后,每個對象是不知道自己的位置、大小等信息的,WebKit 根據框模型來計算它們的位置,大小等信息的過程稱為布局計算。
第五章描述過 Frame 類,用于表示網頁的框結構,每個框都有一個 FrameView 類,用于表示框的視圖結構。
FrameView 類主要負責視圖方面的任務,例如網頁視圖大小,滾動、布局計算、繪圖等,它是一個總入口類。 “layout” 和 “needsLayout” ,它們用來布局計算和決定是否需要布局計算,實際的布局計算則是在 RenderObject 類中。
布局計算根據其計算的范圍大致可以分為兩類:第一類是對整個 RenderObject 樹進行的計算;第二類是對 RenderObject 樹中某個子樹的計算,常見于文本元素或者是 overflow:auto 塊的計算,這種情況一般是其子樹布局的改變不會影響其周圍元素的布局,因而不需要重新計算更大范圍內的布局。
1.3.2 布局計算布局計算是一個遞歸的過程,因為一個節點的大小通常需要先計算它的子女節點的位置,大小等信息。
圖 6-14 描述了 RenderObject 節點計算布局的主要過程,中間省略了很多判斷和步驟,主要邏輯都是由 RenderObject 類的 “layout” 函數來完成。
首先,該函數會判斷 RenderObject 節點是否需要重新計算,通常這需要通過檢查位數組中的相應標記位、子女是否需要計算布局等來確定。
其次,該函數會確定網頁的寬度和垂直方向上的外邊距,這是因為網頁通常是垂直方向上滾動,而水平方向盡量不需要滾動。
再次,該函數會遍歷其每一個子女節點,依次計算它們的布局。每一個元素會實現自己的 “layout” 函數,根據特定的算法來計算該類型元素的布局。如果頁面元素定義了自身的寬高,那么 WebKit 按照定義的寬高來確定元素的大小,而對于像文本節點這樣的內聯元素則需要結合其字號大小及文字的多少等來確定其對應的寬高。如果頁面元素所確定的寬高超過了布局容器包含塊所能提供的寬高,同時其 overflow 的屬性為 visible 或 auto , WebKit 則會提供滾動條來保證可以顯示其所有內容。除非網頁定義了頁面元素的寬高,一般來說頁面元素的寬高是在布局的時候通過相關計算得出來的。如果元素它有子女,則 WebKit 需要遞歸這一過程。
最后,節點根據它的子女們的大小計算得出自己的高度,整個過程結束。
重新布局的情況:
首先,當網頁首次被打開的時候,瀏覽器設置網頁的可視區域(viewport),并調用計算布局的方法。這其實也描述了一種常見的情景,就是當可視區域發生變化的時候,WebKit 都需要重新計算布局,這是因為網頁的包含塊的大小發生了改變。
其次,網頁的動畫會觸發布局計算。當網頁顯示結束后,動畫可能改變樣式屬性,那么 WebKit 就需要重新計算。
然后,JavaScript 代碼通過 CSSDOM 等直接修改樣式信息,它們也會觸發 WebKit 重新計算布局。
最后,用戶的交互也會觸發布局計算,例如翻滾網頁,這會角觸發新區域布局計算。
CSS 的布局計算是以包含塊和框模型為基礎的,這表示這些元素的布局計算都依賴于塊,例如 “div” 通常就是一個塊,如前面所述它們通常是在垂直方向上展開。
但是,CSS 標準也規定了行布局形式,這就是內聯元素。內聯元素表現的是行布局形式,就是說這些元素以行進行顯示。
以 “div” 元素為例,如果設置屬性 “style” 為 “displa: inline” 時,則該元素是內聯元素,那么它可能與前面的元素在同一行。如果該元素沒有設置這個屬性時,則是塊元素,那么在新的行里顯示。這顯然會增加處理的復雜性,為此,WebKit 的處理方式是 ——對于一個塊元素對應的 RenderObject 對象,它的子女要么都是塊元素的 RenderObject 對象,要么都是非內聯元素對應的 RenderObject 對象,這可以通過建立匿名塊(Anonymous Block)對象來實現。
布局計算相對也是比較耗時間的,更糟糕的是,一旦布局發生變化,WebKit 就需要后面的重新繪制操作。另一方面,減少樣式的變動而依賴現在 HTML5 的新功能可以有效地提高網頁的渲染效率。
總結匹配算法結合 CSS 規則來設置樣式
選擇器就是選中某個元素的
框模型就是常說的盒子模型,包含 margin、border、padding、content
CSSOM 稱為 CSS 對象模型,JavaScript 可以獲取和操作 CSS 屬性。
CSS 解釋過程是指從 CSS 字符串經過 CSS 解釋器處理后變成渲染引擎內部規則的表示過程。
當 WebKit 創建 RenderObject 對象之后,每個對象是不知道自己的位置、大小等信息的,WebKit 根據框模型(Frame 類的 FrameView)來計算它們的位置,大小等信息的過程稱為布局計算
布局計算是一個遞歸的過程,而且還會發生重新布局。
最后希望本文對你有點幫助。
下期分享 第七章 渲染基礎 敬請期待。
對 全棧開發 有興趣的朋友可以掃下方二維碼關注我的公眾號 —— 愛寫bugger的阿拉斯加
分享 web 開發相關的技術文章,熱點資源,全棧程序員的成長之路。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/97551.html
摘要:書接上文瀏覽器內核之解釋器和模型本文剖析的解釋器和樣式布局。根據生成解釋器類。而后將解釋后的信息設置到元素的屬性的樣式中,然后設置標記表明該元素需要重新計算樣式,并觸發重新計算布局。 showImg(https://segmentfault.com/img/remote/1460000016215814); 微信公眾號:愛寫bugger的阿拉斯加如有問題或建議,請后臺留言,我會盡力解決...
摘要:響應由三個部分組成,分別是狀態行消息報頭響應正文。詳情參考小汪之前寫的文章瀏覽器內核之解釋器和模型解釋解釋過程是指從字符串經過解釋器處理后變成渲染引擎內部規則的表示過程。 showImg(https://segmentfault.com/img/remote/1460000016404846); 前言 小汪最近在看【WebKit 技術內幕】一書,說實話,這本書寫的太官方了,不通俗易懂。...
摘要:文章同步到技術內幕之頁面渲染過程最近拜讀了傳說中的技術內幕一書,有很大收獲,尤其是對頁面渲染有了較深的認識。解析語法分析,基于詞法解釋器生成的新標記,構建成抽象語法樹,解析器嘗試將其與某條語法規則進行匹配。 文章同步到github《Webkit技術內幕》之頁面渲染過程 最近拜讀了傳說中的《Webkit技術內幕》一書,有很大收獲,尤其是對頁面渲染有了較深的認識。由于功力有限,而且書中設...
摘要:文章同步到技術內幕之頁面渲染過程最近拜讀了傳說中的技術內幕一書,有很大收獲,尤其是對頁面渲染有了較深的認識。解析語法分析,基于詞法解釋器生成的新標記,構建成抽象語法樹,解析器嘗試將其與某條語法規則進行匹配。 文章同步到github《Webkit技術內幕》之頁面渲染過程 最近拜讀了傳說中的《Webkit技術內幕》一書,有很大收獲,尤其是對頁面渲染有了較深的認識。由于功力有限,而且書中設...
摘要:文章同步到技術內幕之頁面渲染過程最近拜讀了傳說中的技術內幕一書,有很大收獲,尤其是對頁面渲染有了較深的認識。解析語法分析,基于詞法解釋器生成的新標記,構建成抽象語法樹,解析器嘗試將其與某條語法規則進行匹配。 文章同步到github《Webkit技術內幕》之頁面渲染過程 最近拜讀了傳說中的《Webkit技術內幕》一書,有很大收獲,尤其是對頁面渲染有了較深的認識。由于功力有限,而且書中設...
閱讀 743·2021-10-09 09:44
閱讀 2016·2021-09-22 15:54
閱讀 5056·2021-09-22 10:55
閱讀 1442·2019-08-29 18:41
閱讀 777·2019-08-29 11:24
閱讀 2103·2019-08-28 18:20
閱讀 1030·2019-08-26 11:51
閱讀 3049·2019-08-26 11:00