Web效能優化之CSS效能優化篇
非常感謝原文作者的分享,個人覺得非常有用.所以將原文進行翻譯,如果有錯誤,麻煩回覆指出
附上原文地址
什麼是高效的CSS?不同的選擇器對效能的影響如何?是花括號裡的屬性重要還是選擇器重要?.
我們在做優化網站的效能時,CSS的優化往往是最後的選擇.因為有更多的優化方案可以帶來比CSS優化更顯著更快速的收益.
然而,對一個CSS庫進行優化卻可以為使用者帶來更好的體驗
每當大家討論CSS的速度時,往往大家會引用Steve Souders的屬性選擇器慢或者是偽類選擇器慢的結論.然而隨著現代瀏覽器的發展,我覺得驗證諸如"屬性選擇器慢"或"偽選擇器慢"之類的反而變得沒有太大的意,應該把效能的提升放在括號內而不是括號外才是我們應該關心的事情
但是除了引用Nicole Sullivand的文章來支援我的假設,選擇器不同並不重要,在這之前我從來沒有真正測試過這個理論;因為我的天賦不足和缺乏完美的分析頭腦使我無法嘗試,我只能進行一些簡單的嘗試
選擇器測速
<script type="text/javascript">
;(function TimeThisMother() {
window.onload = function(){
setTimeout(function(){
var t = performance.timing;
alert("Speed of selection is: " + (t.loadEventEnd - t.responseEnd) + " milliseconds");
}, 0);
};
})();
</script>
並且,我設定了一個非常簡單的測試。20個不同的選擇器,都有一個相同的、巨大的DOM,由下面1000個相同的DOM組成
<div class="tagDiv wrap1">
<div class="tagDiv layer1" data-div="layer1">
<div class="tagDiv layer2" >
<ul class="tagUl">
<li class="tagLi"><b class="tagB"><a href="/" class="tagA link" data-select="link">Select</a></b></li>
</ul>
</div>
</div>
</div>
測試的方式就是通過不同規則的選擇器來讓最內部的a標籤的字型變為紅色,每次測試的結果為每個瀏覽器的5次平均值.在測試中,我實際是運行了十次,而因為前五次的結果往往是有異常的,所以我們只取後5次的結果.
需要注意的是,我們關注點是不同選擇器在同一瀏覽器上的表現,而不是瀏覽器之間相互的PK.所以在關注下面表格時,從上往下一列一列的看才是合適的.
下面就是測試的結果(單位ms):
序號 | CSS測試用例 | IE11 | Google Chrome 65 | Mozilla Firefox 55 |
---|---|---|---|---|
1 | [data-select] | 69 | 73.2 | 121.4 |
2 | a[data-select] | 87.8 | 59.8 | 116.4 |
3 | [data-select=”link”] | 98.4 | 56.6 | 108 |
4 | a[data-select=”link”] | 95.5 | 55 | 104.4 |
5 | div[data-div=”layer1”] a[data-select=”link”] | 82.6 | 56.6 | 104 |
6 | a:after | 105 | 68.2 | 121 |
7 | .tagA.link | 79.2 | 59 | 108 |
8 | .tagUl .link | 95.2 | 55.4 | 109.8 |
9 | .tagB > .tagA | 82.4 | 54.2 | 107.8 |
10 | [class^=”wrap”] | 85.2 | 57.6 | 119.2 |
11 | div:nth-of-type(1) a | 79 | 54 | 104.4 |
12 | div:nth-of-type(1) div:nth-of-type(1) a | 93.8 | 54 | 96.6 |
13 | div.wrapper > div.tagDiv > div.tagDiv.layer1 > div.tagDiv.layer2 > ul.tagUl > li.tagLi > b.tagB > a.tagA.link | 94.2 | 52.8 | 101.4 |
14 | .tagLi .tagB a.tagA.link | 80.6 | 57 | 103.4 |
15 | * | 78.6 | 53.6 | 98.3 |
16 | a | 96.6 | 55.2 | 103.8 |
17 | div a | 95.8 | 59.6 | 122.8 |
18 | div ul a | 82 | 60.8 | 120.8 |
19 | div ul a:after | 102.8 | 69.6 | 130.2 |
20 | .link | 79.6 | 57 | 119 |
最大的差異 | 36 | 20.4 | 34 | |
最慢的選擇器序號 | 19 | 1 | 19 |
這意味著這什麼?
經過我多次的測試,儘管同瀏覽器下,不同的選擇器確實會有一定速度差異,但還是無法從得到的結果中推斷出哪個選擇器最慢.
不過我們可以確定的是,使用類選擇器,不僅可以和選擇其他選擇器擁有一樣的速度擁有一樣的執行速度,而且還可以使你的CSS更具模組化的特徵.
對於我們來說,上述測試中擁有1000個DOM,並且對於使用者訪問網站時最快與最慢的選擇器之間差別也並不足以影響體驗,它已經證實了擔心使用何種選擇器型別是一件浪費時間的事情,因為我們還有更加重要的事情去做
在原文部落格中 ,作者與WebKit工程師本傑明普爾的探討是非常有趣的,下面引用了一些資訊:
對於載入一個頁面來說,有太多其他的因素參與,而CSS的載入只是其中的一小部分。
咱們以測試10的 [class^=”wrap”] 選擇器為例
~10% 的時間用於光柵化圖元
~21% 的時間用於元素放置佈局
~48% 的時間用於解析與DOM樹的構建
~8% 的時間用於CSS解析
~5% 的時間用於收集樣式 – 而這一部分才是我們應該測試的地方
剩下來的時間分佈在一些小的函式上
通過上面的測試,我們假設最快的選擇器的速度為100ms。其中,5 ms將被用於收集樣式。
假設下載另外一個選擇器的速度比第一個選擇器慢3倍,那麼它的載入時間就應該為110ms.
那麼,在測試報告中應該為300%的差異,而不是現在的10%
基於這一點,原文作者回答說,雖然我理解本傑明所指的是什麼,但我的測試只是為了說明我在這篇文章中的觀點 ——
在其他條件不變的情況下,不同的選擇器的使用並不會影響效能
本傑明花時間回答了更多的細節:
我完全同意優化選擇器沒有太多的必要,不過我跟你的原因並不相同:
通過檢查選擇器,幾乎不可能預測給定選擇器的最終效能影響。在引擎中,選擇器被重新排序、分割、收集和編譯。要知道給定選擇器的最終效能,您必須知道選擇器是如何收集的,它是如何編譯的,最後是DOM樹是什麼樣子的?
所有這些在不同的引擎之間是非常不同的,這使得整個過程更加難以預測。
我反對web開發人員優化選擇器的第二個理由是,它們可能會使事情變得更糟。關於選擇器的錯誤資訊比正確的瀏覽器相容資訊要多。想要把它做好幾乎不可能
然而在開發中,人們會發現CSS的效能問題,並開始一個接一個地刪除樣式規則,直到問題解決。我認為這是正確的做法,這很容易,而且會帶來正確的結果。
原因與結果
如果頁面上的DOM元素數量減少了一半,那麼所有測試的速度理應都是相對應的減少.但是,很多時候DOM物件的數量並不能大幅度的減少.這讓我想知道CSS中未使用的樣式的數量會不會對效能產生影響?
另一個測試:我從fiatuk網站抓取了一個臃腫的樣式表。它大約有3000行CSS。所有這些不相關的樣式都被插入到一個最終的檔案中,這個檔案中的樣式是將我們的DOM物件中的所有的內部a節點變成紅色。我在每個瀏覽器上都做了相同的平均結果
然後我把一半的規則去掉,然後重複測試來進行比較。這裡是結果(單位:ms):
Test | Chrome 34 | Firefox 29 | Opera 19 | IE9 | Android 4 |
---|---|---|---|---|---|
所有的樣式 | 64.4 | 237.6 | 74.2 | 436.8 | 1714.6 |
一半的樣式 | 51.6 | 142.8 | 65.4 | 358.6 | 1412.4 |
當一半的樣式被刪除時,你可以看到Firefox的東西下降了很多(大約1500行)。在這一點上,Android裝置的速度也接近於最慢的選擇器的速度。
刪除未使用的樣式
這種恐怖場景對你來說是不是很熟悉?具有各種選擇器的巨大的CSS檔案(通常使用的選擇器甚至都不工作),更具體的選擇器的塊更大,更深入,不適用的字首,雜亂的id,檔案大小為50-80KB(有時更多)。
如果您正在處理一個有一個像這樣臃腫的CSS檔案的程式碼庫,那麼沒有人確切地知道所有的樣式實際上是幹什麼的
處理這個問題似乎比對所使用的選擇器吹毛求疵更有意義。它將產生雙倍的影響;使用者下載的程式碼更少,這是一個速度提升。
但是同樣,這對CSS的實際效能也沒有幫助
括號內的效能
我執行的最後一個測試是配置一堆“昂貴”的CSS來訪問頁面
.link {
background-color: red;
border-radius: 5px;
padding: 3px;
box-shadow: 0 5px 5px #000;
-webkit-transform: rotate(10deg);
-moz-transform: rotate(10deg);
-ms-transform: rotate(10deg);
transform: rotate(10deg);
display: block;
}
以下是結果:
Test | Chrome 34 | Firefox 29 | Opera 19 | IE9 | Android 4 |
---|---|---|---|---|---|
” 昂貴的樣式” | 65.2 | 151.4 | 65.2 | 259.2 | 1923 |
在這裡,所有的瀏覽器都至少比最慢的選擇器測試慢了1.5倍,而Android裝置比最慢的選擇器測試慢了1.3倍,但這還不是全部。 試試看滾動瀏覽器,頁面的樣式重繪會讓你的電腦崩潰.
實際上,我們在括號裡的屬性才是真正影響效能的。這是有理由的,一直滾動一個擁有”昂貴”的,不停需要重繪的並且佈局一直在變化的頁面將會給電腦帶來壓力。
什麼是”昂貴”的樣式?
我們怎麼知道什麼是“昂貴”的樣式?值得慶幸的是,我們可以將平時的經驗應用到這一點上.任何需要瀏覽器在繪圖前進行操作/計算的東西都將更加昂貴。例如,框陰影、圓角、透明度、過度之類的樣式——如果效能是您的優先順序,那麼任何類似的東西都是您最大的敵人
結論
- 在現代瀏覽器中大多數的選擇器速度都非常快,因此使用不同的選擇器來優化效能是沒有必要的;
- 過度使用的樣式與從未使用的樣式所佔比例比選擇任何選擇器消耗的效能更多.所以將CSS庫進行拆分,那可能是更好的選擇;
- 如果你的CSS庫由多人編寫,那麼可以使用UnCSS這樣的工具來自動刪除未被使用的樣式;
- 明智的使用花括號內的屬性才能贏的效能上的收益.在優化時,首先尋找”昂貴”的樣式,會為你和使用者帶來最大的收益