網頁制作poluoluo文章簡介:如果你非常在意頁面的性能那千萬別使用CSS3選擇器。實際上,在所有浏覽器中,用 class 和 id 來渲染,比那些使用同胞,後代選擇器,子選擇器(sibling, descendant and child selectors)對頁面性能的改善更值得關注。
一些關於CSS選擇器性能的討論引起了我的興趣。
第一個是Shaun Inman寫的《合格的CSS選擇器(CSS Qualified Selectors)》,實際上這篇博文並沒有提到CSS性能,不過有一個來自David Hyatt(Safari 和 WebKit 的架構師,同時為 Mozilla, Camino, Firefox 工作)的評論:
如果你非常在意頁面的性能那千萬別使用CSS3選擇器。實際上,在所有浏覽器中,用 class 和 id 來渲染,比那些使用同胞,後代選擇器,子選擇器(sibling, descendant and child selectors)對頁面性能的改善更值得關注。
接下來的一篇博文很神奇。Jon Sykes做了一個系列的文章來測試CSS性能:第一部分, 第二部分, 第三部分,其中 第三部分非常值得一讀。這使我確信優化CSS選擇器是頁面性能優化的一個關鍵步驟。
但是,有兩件事一直困擾著我。首先,大量的DOM元素和CSS規則。頁面包含60000個DOM元素和20000條CSS規則。這使浏覽器非正常的運行(下面將證明這點)。下面的統計表格為美國10大網站的比較:
第二件困擾我的事情是測試以多大頁面為基准?我想解決的問題是:無效率的CSS選擇器會拖慢頁面嗎?所有測試的5個頁面包含20000個a元素(嵌套在P, DIV, DIV, DIV內部)(譯注:使用同樣的HTML頁面),不同的是CSS:基准(沒有CSS)(譯注:下圖中的baseline),標簽選擇器(tag selector )(a標簽有一條CSS規則)(譯注:下圖中的tag),20000個class選擇器(class selectors)(譯注:下圖中的class),20000個子選擇器(child selectors)(譯注:下圖中的child),20000個後代選擇器(descendant selectors)(譯注:下圖中的descendant)。後面3個頁面的大小都超過了3M,而基准及標簽選擇器的頁面則只有1.8M。
接下來調整為:
我在12個浏覽器上進行了測試 。頁面呈現時間是用嵌在頭部和底部的腳本來測量(所有測試在本地運行)。測試結果如下圖(我沒有測試Oprea 9.63,你可以下載csv格式的數據, 這裡是測試頁面):
性能隨浏覽器而改變;奇怪的是,兩個新浏覽器IE 8 和 Firefox 3.1反而是最慢的 所有測試是在同一台PC機的不同浏覽器,不同PC機的不同浏覽器可能有不同的性能特點。這個測試的目的不是比較各浏覽器的性能,而是為了測試浏覽器如何處理逐漸復雜的CSS選擇器。
【修訂:更深入的比較Firefox 3.0和3.1,我發現這台PC上的Firefox 3.1和IE 8遜於其他PC機。即使再進行測試,也會由於不同PC的硬件差異導致不同的結果,所以,不要用這些數據來比較浏覽器。】
毫不意外,越復雜的頁面(子選擇器和後代選擇器)通常性能越差。最大的意外在於第四個頁面居然是最差的。所有的浏覽器平均慢了50毫秒,觀察最大的(IE 6&7, FF3)平均只有20毫秒。對現在70%+的用戶來說,改進CSS選擇器只能提高20毫秒。
請記住,這些測試接近最壞的情況。20個a標簽嵌在P, DIV, DIV, DIV導致總共有6000個DOM元素,這是10大站點中最復雜兩個網站(見表一)的兩倍大。另外,測試的頁面含有2000個極端無效的CSS規則,一般的網站大約有三分之一(譯注:網站本身的CSS規則)的子選擇器及後代選擇器。以Fackbook為例,2882個CSS規則裡只有750個極端無效的規則。
為什麼我的測試結果和之前其他人的有些不同?一個不同來自於這極其極端。它成倍的放大於我們通常所用的頁面。在這種情況下,浏覽器面對3M的頁面,60000個DOM元素及20000條CSS規則會有不同的表現。我注意到,我的測試結果在IE6&7中非常不同。我想知道IE在處理CSS選擇器時是否某個規則。為此我測試了子選擇器和後代選擇器頁面,從1000至20000逐漸增加a標簽和CSS規則的數量,結果如下圖所示,IE在18000條CSS規則時陡增。但是IE 6&7 渲染頁面更接近實際,因為在我的測試中,他們的性能竟然是最高的。
基於這些測試我有以下假設:對大多數網站而言,優化CSS選擇器活得的性能提升很小,不值得去計較。有些配合Javascript交互的CSS規則會明顯的拖慢頁面。這是應該關注的焦點。所以我開始關注現實中影響頁面性能的CSS樣式相關的小問題(offsetWidth, :hover)。
譯注: