參考文章:
https://www.w3cplus.com/css3/introduction-to-hardware-acceleration-css-animations.html
http://blog.csdn.net/hsany330/article/details/50925260css
用CSS3動畫替代JS模擬動畫的好處:html
不佔用JS主線程;css3
能夠利用硬件加速;git
瀏覽器可對動畫作優化(元素不可見時不動畫減小對FPS影響)github
下面讓咱們來看一個動畫效果,在該動畫中包含了幾個堆疊在一塊兒的球並讓它們沿相同路徑移動。最簡單的方式就是實時調整它們的 left
和 top
屬性。咱們可使用JavaScript,但咱們將使用CSS動畫來替代。請注意,文中的示例不帶任何前綴,示例中使用了Autoprefixer來確保完整的兼容性。web
.ball-running { animation: run-around 4s infinite; } @keyframes run-around { 0%: { top: 0; left: 0; } 25% { top: 0; left: 200px; } 50% { top: 200px; left: 200px; } 75% { top: 200px; left: 0; } }
這裏有一個動畫按例,點擊按鈕啓動一個JavaScript動畫:chrome
點擊「Start Animation」按鈕以後,你會隱約感受到動畫並非那麼流暢,即便使用電腦上的瀏覽器也會有些卡頓,更不要提在移動端達到 60fps
的流暢效果了。爲了解決這個問題,咱們可使用 CSS transform 中的 translate()
來替代 top
和 left
:canvas
.ball-running { animation: run-around 4s infinite; } @keyframes run-around { 0%: { transform: translate(0, 0); } 25% { transform: translate(200px, 0); } 50% { transform: translate(200px, 200px); } 75% { transform: translate(0, 200px); } }
如今動畫看起來流暢多了。這是爲何呢?這是由於 transform
屬性不會觸發瀏覽器的 repaint,而 left
和 top
則會一直觸發 repaint,下圖是從 chrome 開發者工具的 timeline 面板監測到的數據:瀏覽器
上圖數據中的綠色條紋表示的就是使用 top
和 left
實現動畫時瀏覽器發生的 repaint 操做,從中能夠看出動畫幀數遠低於 60
幀。ide
下圖是使用CSS transform 檢測到的數據:
如你所見,動畫演示期間並無過多的 repaint 操做。
從 chrome 的開發者工具按 ESC
以後選擇 「rendering」 面板,咱們能夠經過選中「Enable piant flashing」來進一步監測 repaint 操做。開啓該選項後,頁面中的 repaint 區域就會被綠色蒙版高亮顯示出來。從新使用 top
和 left
的示例演示的話,你會發現包裹球的那塊區域會一直閃爍綠色的蒙版。
另外一方面,在使用 transform
的示例中,綠色蒙版只會在動畫開始和結束的時候出現。
那麼,爲何 transform
沒有觸發 repaint 呢?簡而言之,transform
動畫由GPU控制,支持硬件加速,並不須要軟件方面的渲染。
瀏覽器接收到頁面文檔後,會將文檔中的標記語言解析爲DOM樹。DOM樹和CSS結合後造成瀏覽器構建頁面的渲染樹。渲染樹中包含了大量的渲染元素,每個渲染元素會被分到一個圖層中,每一個圖層又會被加載到GPU造成渲染紋理,而圖層在GPU中 transform
是不會觸發 repaint 的,這一點很是相似3D繪圖功能,最終這些使用 transform
的圖層都會由獨立的合成器進程進行處理。
在咱們的示例中,CSS transform
建立了一個新的複合圖層,能夠被GPU直接用來執行 transform
操做。在chrome開發者工具中開啓「show layer borders」選項後,每一個複合圖層就會顯示一條黃色的邊界:
示例中的球就處於一個獨立的複合圖層,移動時的變化也是獨立的:
此時,你也許會問:瀏覽器何時會建立一個獨立的複合圖層呢?事實上通常是在如下幾種狀況下:
<video>
和 <canvas>
標籤z-index
屬性等一下,上面的示例使用的是 2D transition 而不是 3D 的 transforms 啊?這個說法沒錯,因此在timeline中咱們能夠看到:動畫開始和結束的時候發生了兩次 repaint 操做。
3D 和 2D transform 的區別就在於,瀏覽器在頁面渲染前爲3D動畫建立獨立的複合圖層,而在運行期間爲2D動畫建立。動畫開始時,生成新的複合圖層並加載爲GPU的紋理用於初始化 repaint。而後由GPU的複合器操縱整個動畫的執行。最後當動畫結束時,再次執行 repaint 操做刪除複合圖層。
並非全部的CSS屬性都能觸發GPU的硬件加速,實際上只有少數屬性能夠,好比下面的這些:
transform
opacity
filter
爲了不 2D transform 動畫在開始和結束時發生的 repaint 操做,咱們能夠硬編碼一些樣式來解決這個問題:
.example1 { transform: translateZ(0); } .example2 { transform: rotateZ(360deg); }
這段代碼的做用就是讓瀏覽器執行 3D transform。瀏覽器經過該樣式建立了一個獨立圖層,圖層中的動畫則有GPU進行預處理而且觸發了硬件加速。
經過-webkit-transform:transition3d/translateZ開啓GPU硬件加速以後,有些時候可能會致使瀏覽器頻繁閃爍或抖動,能夠嘗試如下辦法解決之:
-webkit-backface-visibility:hidden; -webkit-perspective:1000;
推薦兩種實時監測網頁渲染幀速率的方法:
1.Chrome的DevTool中TimeLine的Frame模塊
2.地址欄輸入」chrome:flags」搜索」fps」,將」FPS計數器」開啓,瀏覽器重啓後右上角會實時顯示幀速率。