如何撰寫有效率的CSS選擇器(CSS Selector)
| 2011/10/11 | 5 則迴響
高效率的CSS選擇器(Selector)表示法不是一個新的主題,對於網頁設計師而言,知道如何撰寫CSS,是一個基本的技術能力,而了解如何撰寫高效率的CSS則能讓網頁設計師的CSS作品獲得更好的品質。
注意:這裡所指的不是讓開發者很有效率的寫CSS,而是讓開發者寫出來的CSS Selector能很有效率的被瀏覽器執行。
本篇描述的規則,比較適用於非常需要全面提升「速度」的網站,像是每個頁面的DOM元素都超過1000個以上的網站。如果是像我這種小小的部落格,提升的效率就完全不明顯,但身為專業的網頁設計師,你還是必須把這些規則放在心上。
CSS 選擇器(Selectors)
CSS 選擇器你應該不陌生,我們可以透過基本的選擇器去指定要處理的DOM元素,像是指定標籤(div,span,body…)、ID(#header)、Class(.post)等選擇器。
還有一些較不常見的摸擬類別(pseudo-classes),如 :hover,或更為複雜的CSS3及regex選擇器,如 :first-child或 [class^=”grid-“] 表示挑出所有類別名稱以grid-為開頭的元素。
而根據網站效率專家 Steve Souders 指出,各種CSS選擇器的效率由高至低排序如下:
1. ID (#id)
2. Class (.class)
3. Type (即HTML標籤,如div)
4. 鄰接選擇器 (如: h2+p,僅作用於鄰接h2的p元素)
5. Child (如: li>ul)
6. Descendant (如:ul a)
7. Universal (*)
8. 屬性 (如: [type=”text”])
9. 摸擬類別/元素 (如: a:hover)
值得注意的是,雖然ID在技術性上來說比較快,但差異其實很微小。在Windows上的Firefox6上測試,ID的reflow速度還比Class慢。但兩者間reflow速度的差距根本不值一提。
註1:reflow是指css在為網頁加上樣式的過程之一。整個CSS繪製過程會先建立DOM,再進行reflow來確定各元素的位置,最後再進行繪製(render)樣式的動作。這裡有個reflow Mozilla官網的過程影片:
如果影片失效,請點選這裡,可以看見reflow奇妙的工作方式。
註2:測試方式是用Steve Sounders製作的工具:css-selectors
接合選擇器
你還可以用像是#nav a這種接合(combining)多個選擇器的選擇器,它的意思是「找到所有在ID為nav的元素下的a元素」。我們以自然語言的閱讀方式,來閱讀這種接合選擇器的方式,通常就是這樣用「由左至右」的方式來讀,但是瀏覽器不是這樣讀的,瀏覽器是用「由右至左」的方式來理解選擇器規則的。
這是為了效率而設計的讀取方式,理由可參考這個討論串。於是,瀏覽器就從DOM樹的上至下開始它的剖析查找旅程。
關鍵選擇器 (key selector)
關鍵選擇器就是最靠接合選擇器右邊的選擇器,例如:#nav a,關鍵選擇器就是a,它就是瀏覽器第一個尋找的規則。是的,瀏覽器會先找出所有的a元素,還記得上面我們剛討論過的效率排行嗎?此時就是該選擇器效率表現的時刻。找出所有的a元素後,接著它會回頭去看DOM樹,去找看是否有a元素是住在ID為nav的元素之中。
因此,以下的選擇器查找規則,就不是非常有效率:
[css]
#content *{}
[/css]
這樣的選擇器會先找出「所有」頁面上的元素,接著再找是否有任何元素是位於#content底下的。如此的查找成本非常昂貴。
所以,運用這樣的知識,我們可以為訂定CSS樣式做出更好的決策。想像一下,如果你有一個充滿大量資料的網頁,而你是一個超級大站。在如此頁面裡,有成千上百個a元素。裡頭有一小塊區域的連結,是專門留給社群連結的區塊,它們都放在ID為social的ul元素裡,假設裡面有Twitter、Facebook、Google+等連結。因此,在這個頁面裡,我們共有三個社群連結,和其他成千上百個連結。
在這樣的頁面裡,使用以下這個選擇器,毫無疑問是非常沒有效率的表示法:
[css]
#social a{}
[/css]
如果要改善這個表示法,我們可以為#social裡頭的a,加上特定的class,例如:.social-link。但只標上 .social-link 似乎有點違背精實運用CSS類別的好習慣,因為這看來沒什麼意義,要達成折衷用法,我們可以這樣寫:
[html]
<!– 略 –>
<ul id="social">
<li><a href="#" class="social-link twitter">Twitter</a></li>
<li><a href="#" class="social-link facebook">Facebook</a></li>
<li><a href="#" class="social-link gplus">Google+</a></li>
</ul>
<!– 略 –>
[/html]
因此,我們的選擇器就可以改成:
[css]
#social .social-link{}
[/css]
這個新的選擇器將比對「遠低於」先前所需比對的元素,這表示瀏覽器就可以快速的找到目標元素,並且快速的完成樣式的繪製。
過份限制的選擇器
接著我們進一步來看其他的最佳化建議。這是一個「過份限制」的選擇器例子:
[css]
html body .wrapper #content a{}
[/css]
這是一個典型限定過了頭的選擇器例子,其中至少有三個元素是多餘的,拿掉後剩下:
[css]
#content a{}
[/css]
這表示,在瀏覽器查找到#content後,不用再進一步去找.wrapper、body和html,因為#content是唯一的,找到#content後,其後的查找都是多餘的。
再看一個例子:
[css]
ul#nav li a{}
[/css]
就可改成:
[css]
#nav a{}
[/css]
知道這樣的規則後,你就不會再輕易的寫出像下面這種看來很炫,但卻沒啥效率的表示式了:
[css]
div:nth-of-type(3) ul:last-child li:nth-of-type(odd) *{ font-weight:bold }
[/css]
另外,jQuery所支援的CSS Selector,讀取方式也是從右至左的。
參考文章:http://csswizardry.com/2011/09/writing-efficient-css-selectors/
標籤:css
本文作者是Audi Lu
5 則留言
關於【過份限制的選擇器】
想請教一下
若使用SPSS或是Compass/Compass.app之類 加速CSS開發的輔助程式
該如何避免這種過份限制的問題呢?
(
因為層疊式的SPSS規則似乎較會出現 其實不必出現的親代選擇器
但是spss這類程式寫出來的東西卻似乎又比較好維護XD
)
感謝您~
R+您好,
對於Compass我還只是新手,並不了解如何避免過份限制的問題。
謝謝您的留言!
但是還是要讓開發者可以很有效率的寫CSS,才能讓CSS Selector很有效率的被瀏覽器執行,噗
您好,我同意讓開發者很有效率的寫CSS也很重要,這可能是類似像compass/sass, LESS這類css preprocessor工具的目標,是另一個有趣的主題,我也還在學習中。:)
很棒的文章,改進了不少 CSS 觀念,感謝分享 🙂