transform和position
position + top/left的效果
下面我們來看一個動畫效果(類似平時頁面滾動功能),在該動畫是讓一個球沿著某種路徑移動。最簡單的方式就是實時調(diào)整它們的left和top屬性,使用css動畫實現(xiàn)。
<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的改變會觸發(fā)瀏覽器的reflow和repaint,整個動畫過程都在不斷觸發(fā)瀏覽器的重新渲染,這個過程是很影響性能的。
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>
這個時候我們就會發(fā)現(xiàn)整個動畫效果流暢了很多,在動畫移動的過程中也沒有發(fā)生repaint和reflow。那么為什么transform沒有出發(fā)repaint呢?原因就是transform動畫由GPU控制,支持硬件加速,并不需要軟件方面的渲染。
硬件加速工作原理
瀏覽器收到頁面文檔后,會將文檔中的標記語言解析為DOM樹,DOM和CSS結(jié)合后形成瀏覽器構(gòu)建頁面的渲染樹,渲染樹中包含了大量的渲染元素,每一個渲染元素會被分到一個圖層中,每個又會被加載到GPU形成渲染紋理,而圖層在GPU中transform是不會觸發(fā)repaint的,這一點非常類似3D繪圖功能,最終這些使用transform的圖層都會使用獨立的合成器進程進行處理,移動時的變化也是獨立的,不會影響到頁面的其他元素,造成重排重繪是因為影響到頁面的其他圖層元素導致的,可以理解為其他元素都是在一個圖層空間,所以一個圖層移動其他的也會收到影響,而transform創(chuàng)建了一個新的復合圖層,它會被GPU獨立執(zhí)行transform操作,跟其他圖層互不影響,所以不會引起重排重繪。
此時,你也許會問瀏覽器什么時候會創(chuàng)建一個獨立的復合圖層呢?事實上一般是在以下幾種情況下:
- 3D或者CSS transform
- video或canvas標簽
- CSS filters
- 元素覆蓋時,比如使用了z-index屬性
等一下,上面的示例使用的是2Dtransform而不是3D的transform,因為在動畫開始和結(jié)束的時候觸發(fā)了兩次repaint操作。3D和2D transform的區(qū)別就在于,瀏覽器在頁面渲染前為3D動畫創(chuàng)建獨立的復合圖層,而在運行期間為2D動畫創(chuàng)建。
動畫開始時,生成新的復合圖層并加載為GPU的紋理用于初始化repaint,然后由GPU的復合器操作整個動畫的執(zhí)行,最后當動畫結(jié)束時,再次執(zhí)行repaint操作刪除復合圖層。
transform為什么不會引發(fā)重排
因為GPU進程會為其開啟一個新的復合圖層,不會影響默認復合圖層(就是普通文檔流),所以并不會影響周邊的 DOM 結(jié)構(gòu),而屬性的改變也會交給 GPU 處理,不會進行重排。使 GPU 進程開啟一個新的復合圖層的方式還有 3D 動畫,過渡動畫,以及 opacity 屬性,還有一些標簽,這些都可以創(chuàng)建新的復合圖層。這些方式叫做硬件加速方式。你可以想象成新的復合圖層和默認復合圖層是兩幅畫,相互獨立,不會彼此影響。降低重排的方式:要么減少次數(shù),要么降低影響范圍,創(chuàng)建新的復合圖層就是第二種優(yōu)化方式。絕對布局雖然脫離了文檔流,但不會創(chuàng)建新的復合圖層,因此當絕對布局改變時,不會影響普通文檔流的 render tree,但是依然會繪制整個默認復合圖層,對普通文檔流是有影響的。普通文檔流就是默認復合圖層,不要介意我交換使用它們?nèi)绻阋褂糜布铀俜绞浇档椭嘏诺挠绊?,請不要過度使用,創(chuàng)建新的復合圖層是有額外消耗的,比如更多的內(nèi)存消耗,并且在使用硬件加速方式時,配合 z-index 一起使用,盡可能使新的復合圖層的元素層級等級最高。
使用GPU渲染元素
能觸發(fā)GPU硬件加速的CSS屬性
(1)transform
(2)opacity
(3)filter
使用硬件加速需要注意的事項
(1)內(nèi)存。如果GPU加載了大量的紋理,那么很容易就會發(fā)生內(nèi)存問題,這一點在移動端尤為明顯。
(2)使用GPU渲染會影響字體的抗鋸齒效果。這是因為GPU和CPU具有不同的渲染機制,即使最終硬件加速停止了,文本還是會在動畫期間顯示的很模糊。
總結(jié)
1、transform會使用GPU硬件加速,性能更好,position + top/left會觸發(fā)大量的重排重繪,性能影響較大。
2、硬件加速的工作原理是創(chuàng)建一個新的復合圖層,然后使用合成線程進行渲染
3、3D和2D動畫的區(qū)別,2D動畫會在動畫開始和動畫結(jié)束時觸發(fā)2次重新渲染
4、使用了GPU可以優(yōu)化動畫小故宮但是不要濫用,會有內(nèi)存問題
5、理解強制觸發(fā)硬件加速的transform技巧,使用對GPU友好的CSS屬性
參考文章:https://zhuanlan.zhihu.com/p/78230297
el-scrollbar是elementui自帶的頁面滾動條,如果用頁面滾動條,我們發(fā)現(xiàn)在ie瀏覽器下卡頓很明顯,但是用el-scrollbar滾動頁面就會感覺會流暢很多,因為頁面滾動會引發(fā)重排重繪,但是el-scrollbar是用transform不會引起,所以用el-scrollbar會感覺流暢很多,轉(zhuǎn)訂單去掉overflow:hidden就會流暢是因為這個樣式會覆蓋el-scrollbar的樣式,