首先咱們要看一下選擇器的「解析」是在什麼時候進行的。html
主要參考這篇「 How browsers work」(http://taligarsiel.com/Projects/howbrowserswork1.htm)來看,瀏覽器渲染的過程以 WebKit 爲例大體以下:瀏覽器
HTML 通過解析生成 DOM Tree(這個咱們比較熟悉);而在 CSS 解析完畢後,須要將解析的結果與 DOM Tree 的內容一塊兒進行分析創建一棵 Render Tree,最終用來進行繪圖。Render Tree 中的元素(WebKit 中稱爲「renderers」,Firefox 下爲「frames」)與 DOM 元素相對應,但非一一對應:一個 DOM 元素可能會對應多個 renderer,如文本折行後,不一樣的「行」會成爲 render tree 種不一樣的 renderer。也有的 DOM 元素被 Render Tree 徹底無視,好比 display:none 的元素。優化
在創建 Render Tree 時(WebKit 中的「Attachment」過程),瀏覽器就要爲每一個 DOM Tree 中的元素根據 CSS 的解析結果(Style Rules)來肯定生成怎樣的 renderer。對於每一個 DOM 元素,必須在全部 Style Rules 中找到符合的 selector 並將對應的規則進行合併。選擇器的「解析」實際是在這裏執行的,在遍歷 DOM Tree 時,從 Style Rules 中去尋找對應的 selector。spa
由於全部樣式規則可能數量很大,並且絕大多數不會匹配到當前的 DOM 元素(由於數量很大因此通常會創建規則索引樹),因此有一個快速的方法來判斷「這個 selector 不匹配當前元素」就是極其重要的。htm
若是正向解析,例如「div div p em」,咱們首先就要檢查當前元素到 html 的整條路徑,找到最上層的 div,再往下找,若是遇到不匹配就必須回到最上層那個 div,往下再去匹配選擇器中的第一個 div,回溯若干次才能肯定匹配與否,效率很低。blog
逆向匹配則不一樣,若是當前的 DOM 元素是 div,而不是 selector 最後的 em,那隻要一步就能排除。只有在匹配時,纔會不斷向上找父節點進行驗證。索引
但由於匹配的狀況遠遠低於不匹配的狀況,因此逆向匹配帶來的優點是巨大的。同時咱們也可以看出,在選擇器結尾加上「*」就大大下降了這種優點,這也就是不少優化原則提到的儘可能避免在選擇器末尾添加通配符的緣由。it