兩張圖解釋CSS動畫的效能

ccforward發表於2016-09-16

在手機上使用CSS動畫時很多時候會感到卡頓,然後網上很多教程說開啟GPU加速 transform: translate3d(0,0,0); 可解決,但是為什麼開啟GPU加速就能讓動畫順滑呢?

我們從瀏覽器內部去理解下

JS是單執行緒的,但是瀏覽器可以開啟多個執行緒,渲染一個網頁需要兩個重要的執行緒來共同完成:

  • Main Thread 主執行緒
  • Compositor Thread 繪製執行緒(我自己翻譯的)

主執行緒的工作:

  1. 執行JS
  2. 計算 HTML 元素的 CSS 樣式
  3. 佈局頁面
  4. 將元素繪製到一個或多個點陣圖中
  5. 把這些點陣圖交給 Compositor Thread 來處理

繪製執行緒的工作:

  1. 通過 GPU 將點陣圖繪製到螢幕上
  2. 通知主執行緒去更新頁面中可見或即將可見的部分的點陣圖
  3. 計算出頁面中那些部分是可見的
  4. 計算出在滾動頁面時候,頁面中哪些部分是即將可見的
  5. 滾動頁面時將相應位置的元素移動到可視區

我們知道如果長時間的執行 JS 會阻塞主執行緒,頁面就會出現各種的卡頓。

而繪製執行緒會盡量的去響應使用者的互動,頁面發生變化時,繪製執行緒會以每秒60幀(因為每秒60幀是最適合人眼的互動,小於60就會明顯感覺到卡頓了)的間隔不斷重繪頁面。

GPU 在如下方面很快:

  • 繪製點陣圖到螢幕上
  • 可不斷的繪製相同的點陣圖
  • 將同一點陣圖進行位移、旋轉、縮放 (就是動畫)

但是在將點陣圖載入到GPU記憶體中有點慢

關於兩張圖的正題來了

PS: 橙色方框的操作比較耗時,綠色方框的操作比較快速

div {
    height: 100px;
    transition: height 1s linear;
}

div:hover {
    height: 200px;
}

一個從 height: 100px 到 height: 200px 的動畫按照下面的流程圖來執行各種操作

圖中有那麼多的橙色方框,瀏覽器會做大量的計算,動畫就會卡頓。

因為每一幀的變化瀏覽器都在進行佈局、繪製、把新的點陣圖交給 GPU 記憶體(這恰好是我們上面提到的GPU的短板)

雖然只改變元素高度但是很可能要同步改變他的子元素的大小,那瀏覽器就要重新計算佈局,計算完後主執行緒再來重新生成該元素的點陣圖。

使用 transform 屬性的動畫

div {
    transform: scale(0.5);
    transition: transform 1s linear;
}

div:hover {
    transform: scale(1.0);
}

流程圖如下

很明顯,這麼少的橙色方框,動畫肯定會流暢。

因為 transform 屬性不會改變自己和他周圍元素的佈局,他會對元素的整體產生影響。

因此,瀏覽器只需要一次生成這個元素的點陣圖,然後動畫開始時候交給 GPU 來處理他最擅長的位移、旋轉、縮放等操作。這就解放了瀏覽器不再去做各種的佈局、繪製等操作。

chrome中執行對比

把上面的demo程式碼在瀏覽器中執行下看下效果,demo地址:

http://ccforward.github.io/demos/css/animation.html

transition: height 1s linear

transform: scale(1.0)

同樣是改變大小的 scale 動畫

相關文章