在前端工程師的平常工做中,使用 CSS 元素選擇器是稀鬆日常的事;不管你是編寫通常的 CSS 仍是須要通過編譯的 SASS,SCSS,LESS等,最終都被編譯成一行一行的 CSS 樣式屬性,最終交給瀏覽器解析並套用。可是你想過沒有這是如何實現的呢?css
咱們先看一下瀏覽器的渲染步驟:html
CSS 在被瀏覽器加載後,會被解析成 CSSOM 樹,並嘗試與 Dom 疊加成渲染樹,隨後進行計算位置、渲染等步驟。這樣看來,CSS 屬性套用的關鍵就在於如何從 CSS 轉化成 CSSOM 樹,以及怎麼把 CSSOM 套用到 DOM 上去。前端
當咱們寫下一組 CSS 樣式時,例如:jquery
#id .class h4 + p { ... }
瀏覽器在解析它時,你可能會認爲 CSS 會按照由左到右的依序找出#id
>.class
>h4
>p
,最後套用,但實際上瀏覽器解析 CSS 的順序是由右到左的 p
>h4
>.class
>#id
。git
很違背直覺對吧?但若是考慮到性能問題,從右到左的解析會比從左到右強不少。程序員
假設這有這樣的 HTML:github
<div id="div1"> <div class="a"> <div class="b"> ... </div> <div class="c"> <div class="d"> ... </div> <div class="e"> ... </div> </div> </div> <div class="f"> <div class="c"> <div class="d"> ... </div> </div> </div> </div>
以及這邊五條 CSS 樣式規則:面試
#div1 .c .d {} .f .c .d {} .a .c .e {} #div1 .f {} .c .d {}
讓咱們模擬一下,若是把 CSS 從左到右解析,將會生成相似這樣的 CSSOM 樹:segmentfault
經過 <div class =「 d」>
中的 .d
來思考,這樣的 CSSOM 樹在套用樣式時,必須對全部的樣式規則進行檢查,以確認樣式規則是否會影響到 .d
,到最後才能肯定可能會影響到 .d
的樣式規則有這三條:瀏覽器
#div1 .c .d
.f .c .d
.c .d
以此類推,每一個 DOM 樹上的元素,都必須便利全部的樣式規則,才能夠取得個別的樣式,這樣會形成大量冗餘的計算,進而嚴重影響性能。
反過來,若是將前面的 CSS 由右到左進行解析,CSSOM 樹則可能會以下:
和前面的例子同樣,從 <div class =「 d」>
中 .d
的角度來看,因爲會被樣式規則影響到的目標元素,已經全都集中在第一層了,因此就不用再去便利整個 CSSOM 樹了,甚至只須要檢查 .d
如下的子屬性變量是否符合實際 DOM 結構,再將全部符合的樣式規則從新取回,便能完成 .d
對元素的樣式規則套用。
從右到左的解析順序可以將全部共享的規則路徑收攏在一塊兒,當瀏覽器進行屬性比對時,就不用再便利整個 CSSOM 樹,大大的減小了無效的比對計算。
也能夠換個方式思考:在 HTML 的結構中,一個元素能夠有無數個子元素,但只能有一個父元素,由子找父(由下往上)搜尋絕對是比較快的。
將 CSSOM 樹解析出來以後就可以和 DOM 結合了嗎?若是真的有這麼簡單就太好了。
除了開發者定義好的 CSS 檔外,還有幾個地方可能會定義樣式規則,影響畫面的渲染:
瀏覽器負責處理 CSS 的部分,會吧前面全部的東西以及 CSS 文件定義的樣式規則分別整理成單獨的樣式規則組(CSS 規則集),內容記載了樣式規則、目標屬性等信息。
爲了提高後面的計算效率,瀏覽器的 CSS 處理內核會按照樣式規則組中個別規則的目標屬性將其分組存放;一共分爲如下四組
這樣在取用時,能夠依據目標元素是否存在這個屬性,快速篩出可能會套用的樣式。
最後是套用規則。瀏覽器會遵循如下順序和樣式規則權重套用全部的樣式規則:
你可能會好奇:爲何 inline style 和開發者定義的 CSS 會被另外處理?
咱們能夠回顧一下瀏覽器渲染的步驟,因爲 inline style 存在於 DOM 元素中,只能在 CSS 套用到 DOM 上時纔會接觸到,事前沒法將二者結合。
實際上瀏覽器在這裏已經完成了優化機制;瀏覽器會自動將狀態一致的元素作樣式快照。狀態一致就是要知足如下幾個條件:
〜
,+
,:first-child
等)因爲上面的條件,以及前面討論到的 CSS 運算過程,編寫 CSS 時也有幾個地方能夠稍微留心一下:
若是可以注意到這類典型的小細節,CSS 效率天然也能夠大幅提高。
認識了 CSS 選擇器以後,你必定會很好奇,JavaScript 的元素選擇器又是怎麼回事呢?這個問題能夠參考 jQuery 的源碼,它是由左到右的解析,至爲何爲何不同,其實在文中也有答案,就留給你思考挖掘吧。