為什麼排版引擎解析 CSS 選擇器時一定要從右往左解析?
參見:
http://www.stevesouders.com/blog/2009/06/18/simplifying-css-selectors/http://calendar.perfplanet.com/2011/css-selector-performance-has-changed-for-the-better/
首先我們要看一下選擇器的「解析」是在何時進行的。
主要參考這篇「 How browsers work」(http://taligarsiel.com/Projects/howbrowserswork1.htm)來看,瀏覽器渲染的過程以 WebKit 為例大致如下:
在建立 Render Tree 時(WebKit 中的「Attachment」過程),瀏覽器就要為每個 DOM Tree 中的元素根據 CSS 的解析結果(Style Rules)來確定生成怎樣的 renderer。對於每個 DOM 元素,必須在所有 Style Rules 中找到符合的 selector 並將對應的規則進行合併。選擇器的「解析」實際是在這裡執行的,在遍歷 DOM Tree 時,從 Style Rules 中去尋找對應的 selector。
因為所有樣式規則可能數量很大,而且絕大多數不會匹配到當前的 DOM 元素(因為數量很大所以一般會建立規則索引樹),所以有一個快速的方法來判斷「這個 selector 不匹配當前元素」就是極其重要的。
如果正向解析,例如「div div p em」,我們首先就要檢查當前元素到 html 的整條路徑,找到最上層的 div,再往下找,如果遇到不匹配就必須回到最上層那個 div,往下再去匹配選擇器中的第一個 div,回溯若干次才能確定匹配與否,效率很低。
逆向匹配則不同,如果當前的 DOM 元素是 div,而不是 selector 最後的 em,那隻要一步就能排除。只有在匹配時,才會不斷向上找父節點進行驗證。
但因為匹配的情況遠遠低於不匹配的情況,所以逆向匹配帶來的優勢是巨大的。同時我們也能夠看出,在選擇器結尾加上「*」就大大降低了這種優勢,這也就是很多優化原則提到的盡量避免在選擇器末尾添加通配符的原因。
現學現賣,如有理解錯誤歡迎指正。Keep in mind that when a browser is doing selector matching it has one element (the one it"s trying to determine style for) and all your rules and their selectors and it needs to find which rules match the element. This is different from the usual jQuery thing, say, where you only have one selector and you need to find all the elements that match that selector.
If you only had one selector and only one element to compare against that selector, then left-to-right makes more sense in some cases. But that"s decidedly not the browser"s situation. The browser is trying to render Gmail or whatever and has the oneit"s trying to style and the 10,000+ rules Gmail puts in its stylesheet (I"m not making that number up).
In particular, in the situation the browser is looking at most of the selectors it"s considering don"t match the element in question. So the problem becomes one of deciding that a selector doesn"t match as fast as possible; if that requires a bit of extra work in the cases that do match you still win due to all the work you save in the cases that don"t match.If you start by just matching the rightmost part of the selector against your element, then chances are it won"t match and you"re done. If it does match, you have to do more work, but only proportional to your tree depth, which is not that big in most cases. On the other hand, if you start by matching the leftmost part of the selector... what do you match it against? You have to start walking the DOM, looking for nodes that might match it. Just discovering that there"s nothing matching that leftmost part might take a while. So browsers match from the right; it gives an obvious starting point and lets you get rid of most of the candidate selectors very quickly. You can see some data at http://groups.google.com/group/mozilla.dev.tech.layout/browse_thread/thread/b185e455a0b3562a/7db34de545c17665 (though the notation is confusing), but the upshot is that for Gmail in particular two years ago, for 70% of the (rule, element) pairs you could decide that the rule does not match after just examining the tag/class/id parts of the rightmost selector for the rule. The corresponding number for Mozilla"s pageload performance test suite was 72%. So it"s really worth trying to get rid of those 2/3 of all rules as fast as you can and then only worry about matching the remaining 1/3. Note also that there are other optimizations browsers already do to avoid even trying to match rules that definitely won"t match. For example, if the rightmost selector has an id and that id doesn"t match the element"s id, then there will be no attempt to match that selector against that element at all in Gecko: the set of "selectors with IDs" that are attempted comes from a hashtable lookup on the element"s ID. So this is 70% of the rules which have a pretty good chance of matching that still don"t match after considering just the tag/class/id of the rightmost selector
via Boris Zbarsky(http://stackoverflow.com/questions/5797014/css-selectors-parsed-right-to-left-why/5813672#5813672)
這只是一種演算法而已,你可以自己寫一個瀏覽器,從左往右解析 CSS 選擇器。
野路子答案:英文順序中一向是先小後大,先具體後寬泛。比如姓名是先名後姓、地址是X號X街X城市X州、日期是月/日/年。私以為西方比較強調個體價值,中國比較注重家族觀念強調繼承與服從。
因為這麼算,對比其他方案,更加高效一些,但是其實真正的選擇器會很智能,有很多種選擇方案。。
用一個哲學來解釋:人可以選擇2條路,而走的時候,只能走一條。在任何熟悉或閱讀信息的書籍或報紙或代碼時,都是一行一行的。從章節角度看,類似一個treeview....單向樹...;你要從右往左匹配也是可以做到的,但沒人那麼寫演算法...Sunday演算法號稱急快速字元串匹配,如果把現有的好多規範弄成從右往左,目測,執行效率會快很多。
推薦閱讀:
※如何寫一個類似 LESS 的編譯工具?
※關於 CSS 的好書有哪些?
※CSS 里的 height 屬性與 line-height 屬性有什麼區別?
※如何評價真阿當在前端領域的技術水平?
※如何解決外邊距疊加的問題?