從css到頁面樣式渲染

寫了這麼多class,color,background,display...; 也許有時候會疑惑,怎麼就顯示在頁面上,改變元素的樣式。

本文簡明介紹整個解析,匹配,渲染過程

css 描述

css 是Cascading Style Sheets的簡寫,是一種樣式表語言。對應多種語法規則,可以爲HTML 指定樣式。

基本規則

圖片描述

圖片來源

css 規則由兩部分組成:選擇器聲明。上圖中element 對應的類選擇器,緊接着聲明(Declaration)

每條聲明由一個屬性(Property)冒號(:)和 一個值(value)分號(;) 組成。

CSS 解析

解析 html 或外部css 文檔,就是將文檔轉化成爲有意義的結構,能夠讓代碼理解。解析結果代表了文檔結構的節點樹,

解析分爲詞法分析 和 語法分析。
解析過程

詞法分析,也是編譯原理中的術語,從左到右一個字符一個字符的讀入源程序,對字符流進行掃描,根據構詞規則識別單詞,。這一過程可以使用lex等工具自動生成。

語法分析,主要任務是在詞法分析的基礎上,將單詞序列組合成各類語法短語,如“程序”, “語句”,“表達式”

解析工作通常會被拆分爲兩個組件:

  1. 詞法分析器,負責將輸入流分解成有效的字符。
  2. 解析器,負責根據不同語言的語法規則來分析文檔結構,最後構造出解析樹。
    詞法分析器知道如何去除不相關的字符,比如空格和換行

具體到css解析,因爲它是上下文無關的語法,可以利用各種解析器進行解析。webkit 使用Flex 和 Bison 解析器生成器,通過css 語法文件自動創建解析器。解析器將CSS文件解析成StyleSheet對象,且每個對象都包含CSS規則。CSS規則包含選擇器和聲明對象。
圖片描述

上圖是 一個像素點的一生的ppt中選出圖片,感興趣可以看看演講視頻,非常直白,css樣式規則會被各種方式索引以便進行快速有效的查找。實現各個樣式屬性的C++ 類,比如ppt中的BorderLeftColor類,是在構建時Python腳本自動生成的。

具體到代碼實現中,webkit 使用CSSRuleSet 對象來保存style rule,在一般規則需要創建時,調用createStyleRule();

瀏覽器從右往左匹配選擇器

在使用css選擇器進行樣式匹配時,儘量少用層級關係,因爲這樣可以減少選擇器匹配的次數,提高css 解析效率。

其實瀏覽器使用從右到左的解析順序,同樣提高了效率。通常在寫css 樣式時,我們一貫的想法是,從左往右解析,從根節點開始,一層一層遍歷匹配,直到所有的選擇器都匹配上了。瀏覽器解析的順序正好相反。

從右往左匹配的好處

簡單回顧下本次話題的上下文,也就是瀏覽器對頁面解析過程:

  1. HTML parser 生成 Dom Tree
  2. css parser 生成 style rules,也就是CSSOM tree。
  3. DomCSSOM匹配完成後,最後結合生成render tree
  4. 根據 render tree 開始 佈局
    ...

clipboard.png

根據這張圖,可以對渲染過程大致瞭解。

回到瀏覽器匹配css 規則上,如果只有一個選擇器 對應匹配一個元素,從左往右匹配看似非常合理,但是正常情況是,一個dom節點,比如<div class="cls1 cls2 cls3" id='id1'></div>,可能對應了無數個css規則,沒有上限,我可以在上面加非常多的樣式。css 匹配效率的關鍵就是如何快速判斷儘可能多的選擇器並不能匹配。

先看看有多層嵌套的css規則。比如 #root .box .wrap i {}, 如果從左往右解析,最左邊開始, 直到最右邊的選擇器i, dom節點上根本沒有i標籤, 遍歷到最後才排除css 規則。

相反,從最右邊的選擇器部分開始匹配,如果不成功,整個匹配過程就可以立刻結束;成功了,繼續往左,匹配父節點,跟樹的深度成正比。所以瀏覽器的匹配方式,可以非常快速的排除大部分的選擇器。

根據2009年在Firefox上做的測試,結論是僅僅從最右邊的選擇器開始檢查,就可以排除70%的規則。快速除去2/3的css規則後,後面只用擔心剩餘的1/3。

樣式作用在DOM元素上

從css文檔被解析器解析完成,將數據保存在對象模型中,獲取所有已解析的樣式規則,結合瀏覽器提供的默認樣式,計算出每個DOM 元素最終的樣式值。保存在ComputedStyle對象模型中,它是由樣式屬性和值形成的map。
並且getComputedStyle 已經暴露出來,在js中通過window.getComputedStyle,可以獲取元素的最終樣式。

共享ComputedStyle

如果多個element的computedStyle不通過計算可以確認它們相等,那麼這些elements只會計算一次樣式,其餘的直接共享該ComputedStyle。

那些規則會共享computedStyle(待驗證):

  1. 該共享的element不能有id 屬性且CSS中還有該id的StyleRule,即使StyleRule 與 element 不匹配
  2. tagName 和 class 屬性必須一樣。
  3. mappedAttribute 必須相同。
  4. 不能使用sibling selector, 比如 :first-child, :last-child.
  5. 不能有style 屬性,哪怕style 屬性相同。他們也不會共享。

       <p style="color:red">p1</p>
       <p style="color:red">p2</p>
       

渲染

頁面繪製到屏幕後,頁面結構的改變也有可能導致渲染樹重新計算,其中重排和重繪是最耗時的部分。

在頁面的生命週期中,隨時都有可能發生重排(Layout)和重繪(Painting)

重排(reflow)

當可見節點位置 及尺寸發生變化時都會發生重排,而且重排開銷比重繪更大。

至少會有一次重排,發生在初始化頁面佈局的時候。

觸發重排的幾種情況:

  1. 添加或刪除可見dom元素
  2. 元素位置改變
  3. 元素尺寸改變,
  4. 文字,內容,字體發生改變
  5. 頁面初始化渲染
    ....

重繪(repaints)

改變元素的外觀屬性(如background-color, border-color, visibility),不影響整個佈局,瀏覽器就會根據元素的新屬性重新繪製。

重繪不會帶來重新佈局

層合成(composite)

DOM樹中每個節點的都對應一個LayoutObject, 擁有相同的座標空間的LayoutObject,屬於同一渲染層(RenderLayers)。

渲染層保證元素按照正確順序合成(composite),正常展示元素的重疊以及元素透明等。

存在一些特殊情況,爲滿足指定條件的LayoutObject會擁有獨立的渲染層,其他layoutobject則和第一個擁有渲染層的父元素公用一個。

利用chrome Devtools查看繪製過程。

打開Chrome Devtools,按下Esc建
在出現的面板上 點擊左上角三點。
clipboard.png

選擇rendering,轉到對應標籤。
clipboard.png

打開後,頁面中閃爍的綠色區域,表示這塊需要重新繪製。
當滾動側邊欄時,會出現整塊綠色

clipboard.png

總結

本文對css整個渲染過程進行簡單介紹,試圖把大量複雜知識點串在一起,至少可以讓平時跟css打交道的我們,瞭解大致是個什麼過程,同時也是對自己學習過程中的一次總結。對於裏面涉及到的概念,都可以作爲一個切入點,去好好研究。

參考鏈接

  1. Things nobody ever taught me about CSS
  2. 縮小樣式計算的範圍並降低其複雜性
  3. 爲什麼瀏覽器讀取css規則的順序是從右到左
  4. why-do-browsers-match-css-selectors-from-right-to-left
  5. 【Hello CSS】第一章-CSS的語法與工作流
  6. 編譯原理之詞法分析、語法分析、語義分析
  7. How Browsers Work: Behind the scenes of modern web browsers
  8. 前端代碼如何通過瀏覽器演化爲屏幕顯示的像素
  9. Webkit CSS引擎分析
  10. 簡化繪製的複雜度、減小繪製區域
  11. 無線性能優化:Composite
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章