CSS動畫之硬件加速

原文地址:css

https://www.w3cplus.com/css3/introduction-to-hardware-acceleration-css-animations.htmlhtml

 

過去幾年,咱們經常會據說硬件加速給移動端帶來了巨大的體驗提高,可是即便對於不少經驗豐富的開發者來講,恐怕對其背後的工做原理也是模棱兩可,更不要合理地將其運用到網頁的動畫效果中了。在本文中,我會和你們分享有關硬件加速的前端技巧。前端

爲何要關心硬件加速

下面讓咱們來看一個動畫效果,在該動畫中包含了幾個堆疊在一塊兒的球並讓它們沿相同路徑移動。最簡單的方式就是實時調整它們的 left 和 top 屬性。咱們可使用JavaScript,但咱們將使用CSS動畫來替代。請注意,文中的示例不帶任何前綴,示例中使用了Autoprefixer來確保完整的兼容性。css3

.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動畫:git

 

點擊「Start Animation」按鈕以後,你會隱約感受到動畫並非那麼流暢,即便使用電腦上的瀏覽器也會有些卡頓,更不要提在移動端達到 60fps 的流暢效果了。爲了解決這個問題,咱們可使用 CSS transform 中的 translate() 來替代 top 和 leftgithub

.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);
  }
}

試試下面的示例:chrome

 

如今動畫看起來流暢多了。這是爲何呢?這是由於 transform 屬性不會觸發瀏覽器的 repaint,而 left 和 top 則會一直觸發 repaint,下圖是從 chrome 開發者工具的 timeline 面板監測到的數據:canvas

CSS動畫之硬件加速

上圖數據中的綠色條紋表示的就是使用 top 和 left 實現動畫時瀏覽器發生的 repaint 操做,從中能夠看出動畫幀數遠低於 60 幀。瀏覽器

下圖是使用CSS transform 檢測到的數據:ide

CSS動畫之硬件加速

如你所見,動畫演示期間並無過多的 repaint 操做。

從 chrome 的開發者工具按 ESC 以後選擇 「rendering」 面板,咱們能夠經過選中「Enable piant flashing」來進一步監測 repaint 操做。開啓該選項後,頁面中的 repaint 區域就會被綠色蒙版高亮顯示出來。從新使用 top 和 left 的示例演示的話,你會發現包裹球的那塊區域會一直閃爍綠色的蒙版。

CSS動畫之硬件加速

另外一方面,在使用 transform的示例中,綠色蒙版只會在動畫開始和結束的時候出現。

那麼,爲何 transform 沒有觸發 repaint 呢?簡而言之,transform 動畫由GPU控制,支持硬件加速,並不須要軟件方面的渲染。

硬件加速的工做原理

瀏覽器接收到頁面文檔後,會將文檔中的標記語言解析爲DOM樹。DOM樹和CSS結合後造成瀏覽器構建頁面的渲染樹。渲染樹中包含了大量的渲染元素,每個渲染元素會被分到一個圖層中,每一個圖層又會被加載到GPU造成渲染紋理,而圖層在GPU中 transform 是不會觸發 repaint 的,這一點很是相似3D繪圖功能,最終這些使用 transform 的圖層都會由獨立的合成器進程進行處理

在咱們的示例中,CSS transform 建立了一個新的複合圖層,能夠被GPU直接用來執行 transform 操做。在chrome開發者工具中開啓「show layer borders」選項後,每一個複合圖層就會顯示一條黃色的邊界:

示例中的球就處於一個獨立的複合圖層,移動時的變化也是獨立的:

CSS動畫之硬件加速

此時,你也許會問:瀏覽器何時會建立一個獨立的複合圖層呢?事實上通常是在如下幾種狀況下:

  • 3D 或者 CSS transform
  • <video> 和 <canvas> 標籤
  • CSS filters
  • 元素覆蓋時,好比使用了 z-index 屬性

等一下,上面的示例使用的是 2D transition 而不是 3D 的 transforms 啊?這個說法沒錯,因此在timeline中咱們能夠看到:動畫開始和結束的時候發生了兩次 repaint 操做。

CSS動畫之硬件加速

3D 和 2D transform 的區別就在於,瀏覽器在頁面渲染前爲3D動畫建立獨立的複合圖層,而在運行期間爲2D動畫建立。動畫開始時,生成新的複合圖層並加載爲GPU的紋理用於初始化 repaint。而後由GPU的複合器操縱整個動畫的執行。最後當動畫結束時,再次執行 repaint 操做刪除複合圖層。

使用 GPU 渲染元素

並非全部的CSS屬性都能觸發GPU的硬件加速,實際上只有少數屬性能夠,好比下面的這些:

  • transform
  • opacity
  • filter

強制使用GPU渲染

爲了不 2D transform 動畫在開始和結束時發生的 repaint 操做,咱們能夠硬編碼一些樣式來解決這個問題:

.example1 {
  transform: translateZ(0);
}

.example2 {
  transform: rotateZ(360deg);
}

這段代碼的做用就是讓瀏覽器執行 3D transform。瀏覽器經過該樣式建立了一個獨立圖層,圖層中的動畫則有GPU進行預處理而且觸發了硬件加速。

若是某一個元素的背後是一個複雜元素,那麼該元素的 repaint 操做就會耗費大量的資源,此時也可使用上面的技巧來減小性能開銷。讓咱們回到第一個示例,而且在球的背後加載一張使用CSS filter模糊後的圖片,最後使用 left 和 top 屬性來操做球的動畫效果。

 

效果太差了!這是由於每次 repaint 都會花費大量的資源處理模糊化的背景。

接下來,使用 transform 技巧重構這一效果:

 

效果還不錯!這是爲何?由於模糊化的背景被移動到了另外一個複合圖層中,而球的每次運動都不會觸發該背景的重繪。

使用硬件加速的注意事項

使用硬件加速並非十全十美的事情,好比:

  • 內存。若是GPU加載了大量的紋理,那麼很容易就會發生內容問題,這一點在移動端瀏覽器上尤其明顯,因此,必定要牢記不要讓頁面的每一個元素都使用硬件加速。
  • 使用GPU渲染會影響字體的抗鋸齒效果。這是由於GPU和CPU具備不一樣的渲染機制。即便最終硬件加速中止了,文本仍是會在動畫期間顯示得很模糊。

新事物

最近瀏覽器提出了一個 will-change 屬性,該屬性容許開發者告知瀏覽器哪個屬性即將發生變化,從而爲瀏覽器對該屬性進行優化提供了時間。下面是一個使用 will-change的示例:

.example {
  will-change: transform;
}

缺點在於目前該屬性的瀏覽器兼容性並非很好,更多信息請參考以下資料:

結論

簡而言之:

  • 使用GPU能夠優化動畫效果
  • GPU渲染動會達到60fps
  • 使用對GPU友好的CSS屬性
  • 理解強制觸發硬件加速的 transform 技巧

著做權歸做者全部。
商業轉載請聯繫做者得到受權,非商業轉載請註明出處。
原文: https://www.w3cplus.com/css3/introduction-to-hardware-acceleration-css-animations.html © w3cplus.com

相關文章
相關標籤/搜索