淺析CSS的效能優化:transform與position區別、硬體加速工作原理及注意事項、強制使用GPU渲染的友好CSS屬性
在網上看到一個這樣的問題: transform與position:absolute 有什麼區別?查閱資料後發現這道題目其實不簡單,涉及到重排、重繪、硬體加速等網頁優化的知識。
一、問題背景
過去幾年,我們常常會聽說硬體加速給移動端帶來了巨大的體驗提升,但是即使對於很多經驗豐富的開發者來說,恐怕對其背後的工作原理也是模稜兩可,更不要合理地將其運用到網頁的動畫效果中了著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。
原文: https://www.w3cplus.com/css3/introduction-to-hardware-acceleration-css-animations.html
商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。
原文: https://www.w3cplus.com/css3/introduction-to-hardware-acceleration-css-animations.html © w3cplus.com
過去幾年,我們常常會聽說硬體加速給移動端帶來了巨大的體驗提升,但是即使對於很多經驗豐富的開發者來說,恐怕對其背後的工作原理也是模稜兩可,更不要合理地將其運用到網頁的動畫效果中了。
1、position + top/left 的效果
下面讓我們來看一個動畫效果,在該動畫中包含了幾個堆疊在一起的球並讓它們沿相同路徑移動。最簡單的方式就是實時調整它們的 left 和 top 屬性,使用 css 動畫實現。
<style>
html,
body {
width: 100%;
height: 100%;
}
.ball-running {
animation: run-around 4s infinite;
width: 100px;
height: 100px;
background-color : red;
position: absolute;
}
@keyframes run-around {
0%: {
top: 0;
left: 0;
}
25% {
top: 0;
left: 200px;
}
50% {
top: 200px;
left: 200px;
}
75% {
top: 200px;
left: 0;
}
}
</style>
<body>
<div class="ball-running"></div>
</body>
在執行的時候,即使是在電腦瀏覽器上也會隱約覺得動畫的執行並不流暢,動畫有些停頓的感覺,更不要提在移動端達到 60fps 的流暢效果了。這是因為top和left的改變會觸發瀏覽器的 reflow 和 repaint ,整個動畫過程都在不斷觸發瀏覽器的重新渲染,這個過程是很影響效能的。
2、transform 的效果
為了解決這個問題,我們使用 transform 中的 translate() 來替換 top 和 left ,重寫一下這個動畫效果。
<style>
html,
body {
width: 100%;
height: 100%;
}
.ball-running {
animation: run-around2 4s infinite;
width: 100px;
height: 100px;
background-color: red;
position: absolute;
}
@keyframes run-around2 {
0%: {
transform: translate(0, 0);
}
25% {
transform: translate(200px, 0);
}
50% {
transform: translate(200px, 200px);
}
75% {
transform: translate(0, 200px);
}
}
</style>
<body>
<div class="ball-running"></div>
</body>
這時候會發現整個動畫效果流暢了很多,在動畫移動的過程中也沒有發生repaint和reflow。
那麼,為什麼 transform
沒有觸發 repaint 呢?原因就是:transform
動畫由GPU控制,支援硬體加速,並不需要軟體方面的渲染。
二、硬體加速工作原理
瀏覽器接收到頁面文件後,會將文件中的標記語言解析為DOM樹,DOM樹和CSS結合後形成瀏覽器構建頁面的渲染樹,渲染樹中包含了大量的渲染元素,每一個渲染元素會被分到一個圖層中,每個圖層又會被載入到GPU形成渲染紋理,而圖層在GPU中 transform是不會觸發 repaint 的,這一點非常類似3D繪圖功能,最終這些使用transform的圖層都會使用獨立的合成器程序進行處理。
在我們的示例中,CSS transform 建立了一個新的複合圖層,可以被GPU直接用來執行 transform 操作。在chrome開發者工具中開啟“show layer borders”選項後,每個複合圖層就會顯示一條黃色的邊界。示例中的球就處於一個獨立的複合圖層,移動時的變化也是獨立的。
此時,你也許會問:瀏覽器什麼時候會建立一個獨立的複合圖層呢?事實上一般是在以下幾種情況下:
(1)3D 或者 CSS transform
(2)video或canvas標籤
(3)CSS filters
(4)元素覆蓋時,比如使用了 z-index 屬性
等一下,上面的示例使用的是 2D transition 而不是 3D 的 transforms 啊?這個說法沒錯,所以在timeline中我們可以看到:動畫開始和結束的時候發生了兩次 repaint 操作。
3D 和 2D transform 的區別就在於,瀏覽器在頁面渲染前為3D動畫建立獨立的複合圖層,而在執行期間為2D動畫建立。
動畫開始時,生成新的複合圖層並載入為GPU的紋理用於初始化 repaint,然後由GPU的複合器操縱整個動畫的執行,最後當動畫結束時,再次執行 repaint 操作刪除複合圖層。
三、使用 GPU 渲染元素
1、能觸發GPU渲染的屬性
並不是所有的CSS屬性都能觸發GPU的硬體加速,實際上只有少數屬性可以,比如下面的這些:
(1)transform
(2)opacity
(3)filter
2、強制使用GPU渲染
為了避免 2D transform 動畫在開始和結束時發生的 repaint 操作,我們可以硬編碼一些樣式來解決這個問題:
.exam1{
transform: translateZ(0);
}
.exam2{
transform: rotateZ(360deg);
}
這段程式碼的作用就是讓瀏覽器執行 3D transform,瀏覽器通過該樣式建立了一個獨立圖層,圖層中的動畫則有GPU進行預處理並且觸發了硬體加速。
3、使用硬體加速需要注意的事項
使用硬體加速並不是十全十美的事情,比如:
(1)記憶體。如果GPU載入了大量的紋理,那麼很容易就會發生記憶體問題,這一點在移動端瀏覽器上尤為明顯,所以,一定要牢記不要讓頁面的每個元素都使用硬體加速。
(2)使用GPU渲染會影響字型的抗鋸齒效果。這是因為GPU和CPU具有不同的渲染機制,即使最終硬體加速停止了,文字還是會在動畫期間顯示得很模糊。
4、will-change
瀏覽器還提出了一個 will-change 屬性,該屬性允許開發者告知瀏覽器哪一個屬性即將發生變化,從而為瀏覽器對該屬性進行優化提供了時間。下面是一個使用 will-change 的示例
.exam3{
will-change: transform;
}
缺點在於其相容性不大好。
總結:
1、transform 會使用 GPU 硬體加速,效能更好;position + top/left 會觸發大量的重繪和迴流,效能影響較大。
2、硬體加速的工作原理是建立一個新的複合圖層,然後使用合成執行緒進行渲染。
3、3D 動畫 與 2D 動畫的區別;2D動畫會在動畫開始和動畫結束時觸發2次重新渲染。
4、使用GPU可以優化動畫效果,但是不要濫用,會有記憶體問題。
5、理解強制觸發硬體加速的 transform 技巧,使用對GPU友好的CSS屬性。
英文原文:http://www.sitepoint.com/introduction-to-hardware-acceleration-css-animations/