建立前端平移動畫爲什麼 translate() 優於 top/right/bottom/left

前言

研究這個問題的原由,源於我在閱讀做曲家與聽衆這篇文章時,看到的這樣一句話。css

例如,我對不少開發者(無論新手仍是老手)仍然使用 CSS 的 top 和 left 而不是 transform 建立平移動畫感到震驚,儘管只要你在除了 8 核 MacBook Pro 以外的設備上進行過測試,就會發現幀率的差異極其明顯。html

看到這句話我也一樣震驚,震驚之處正如做者所言,我就是從未在乎過二者差異而使用 top 和 left 建立平移動畫的人之一。那麼爲何二者會有區別,讓咱們來一探究竟吧。html5

測試用例

其實很慚愧,早在2012年就有許多人在博文中闡述這一事實了,也所以,我能很輕鬆的找到很是棒的demo(來源見參考文獻),以下:canvas

相信讀者在把Macbook Pro增長到必定數量的時候,都能發現二者之間的差別了吧。瀏覽器

深刻背後

如今讓咱們來探究其中的緣由。打開Chrome dev tools,切到Performance選項,記錄一段時間後,選擇某一幀查看各個過程所佔時間。app

首先是top、left的時間線:composer

top、left的時間線

在這一幀中,咱們看到多個步驟佔用了CPU時間。ide

換到translate則變成了大相徑庭的樣子:測試

圖片描述

根本沒有CPU時間。我看了不少幀,除了少部分幀有0.1ms左右的腳本執行時間以外,大部分幀的CPU時間都是0。優化

答案已經很顯然了,使用translate來作平移運動,大部分時間都不須要CPU參與。這個結果和五年前的文章不太相同,但時間已通過了五年,瀏覽器的優化至此地步也不算出乎意料吧。

接下來咱們打開Render,開啓Paint Flashing和Layer Borders。

Rendering

開啓選項

對於top、left咱們會看到以下狀況:

圖片描述

其中綠框是瀏覽器重繪的區域,對於使用position的狀況,瀏覽器要在動畫的執行中不停地繪製綠框中的區域。

而對於transform則是另外一幅場景:

QQ20170726-200457.gif

咱們能夠看到transform的版本咱們的MacBook圖片周圍會多一個框框,這是由於transform會生成一個新的層,而對這個圖層進行變換,對於瀏覽器來講,是不須要重繪的。包括在我點擊「add 10 more macbook」以後,也只有插入元素的時候會引發重繪。一樣,新插入的「MacBook」也各自有獨立的圖層,不會引發重繪。

那麼,Chrome建立層的標準是什麼呢?在Accelerated Rendering in Chrome中有以下表述:

What else gets its own layer? Chrome’s heuristics here have evolved over time and continue to, but currently any of the following trigger layer creation:

  1. 3D or perspective transform CSS properties
  2. <video> elements using accelerated video decoding
  3. <canvas> elements with a 3D (WebGL) context or accelerated 2D context
  4. Composited plugins (i.e. Flash)
  5. Elements with CSS animation for their opacity or using an animated transform
  6. Elements with accelerated CSS filters
  7. Element has a descendant that has a compositing layer (in other words if the element has a child element that’s in its own layer)
  8. Element has a sibling with a lower z-index which has a compositing layer (in other words the it’s rendered on top of a composited layer)

因此,對於咱們的transform動畫,其符合上述第五條規則中的「using an animated transform」,所以會建立本身獨立的層;一樣,咱們也能夠根據上述規則來給top、left方案建立獨立的層來減小重繪。

接下來,根據第一條規則,讓咱們在top、left示例中的.macbook類上面加上這樣一行css:

transform: translateZ(0);

咱們就能看到和translate方案同樣的場景了。

加上3D CSS屬性的position方案

經過查閱資料,我簡單說一下個人理解。Chrome會預先將層的內容繪製成位圖發送給GPU,若是層僅僅是位置與透明度等特定的一些屬性發生變化,而不是內容發生變化,則無需重繪這一位圖。所以不管是translate動畫方案,仍是加上3D變換屬性的top、left方案,因爲其都在獨立的層上,且只是發生位置變化,所以無需重繪。

然而,層並非越多越好。參考Accelerated Rendering in Chrome中的表述。

But beware just blindly creating them, as they’re not free: they take up memory in system RAM and on the GPU (particularly limited on mobile devices) and having lots of them can introduce other overhead in the logic keeps track of which are visible. Many layers can also actually increase time spent rasterizing if they layers are large and overlap a lot where they didn’t previously, leading to what’s sometimes referred to as 「overdraw」. So use your knowledge wisely!

簡單翻譯一下就是:層會佔用系統 RAM 與 GPU(在移動設備上尤爲有限)的內存,而且擁有大量的層會由於記錄哪些是可見的而引入額外的開銷。許多層還會由於過大與許多內容重疊而致使「過分繪製(overdraw)」的狀況發生,從而增長柵格化的時間。關於這一點,在Jank Busting Apple's Home Page中也有所體現。

In this case, too many elements have translateZ(0) applied when only one or two applications are really needed. This is forcing a longer composite time and ultimately giving the animations some jank.

「So use your knowledge wisely!」

參考文獻

相關文章
相關標籤/搜索