CSS will-change 屬性


介紹

如果你注意到在webkit的瀏覽器上“flicker”一些CSS操作(尤其是變形和動畫方面的)的表現,你很可能之前就注意過硬件加速

CPU、GPU和硬件加速

硬件加速意味着Graphics Processing Unit(GPU)會通過代替Central Processing Unit (CPU)做一些負荷比較大的事情,來協助瀏覽器快速渲染頁面,當CSS操作使用硬件加速的時候,通常會使頁面渲染速度加快

顧名思義,CPU和GPU都是計算機處理單元。CPU在電腦主板,幾乎處理電腦的一切操作,有電腦大腦之稱;GPU在顯卡上,負責處理和渲染圖形。此外GPU通過特殊的設計,使其擅長於渲染圖形所需的數學和幾何運算。因此把操作轉嫁到GPU可以獲得顯著的性能提升,同時也可以減少移動設備CPU的爭用。

硬件加速(或者說GPU加速)依賴於瀏覽器渲染頁面使用的layering model,當特定的操作(CSS 3D變形)作用於頁面上的一個元素,元素移動到它自己的layer,在這個layer中元素合一不受頁面其他元素的干擾獨立渲染,然后復合到頁面中去。在這種隔離內容渲染的工作方式下,如果頁面的變化僅僅是該元素的變形,其余部分不必被重新渲染,這會帶來顯著的速度優勢。值得注意的是只有3D變形會有自己的layer,2D變形不會。

CSS的動畫、變形、漸變並不會自動的觸發GPU加速,而是使用瀏覽器稍慢的軟件渲染引擎。然而一些瀏覽器提供了hardware acceleration by means of certain properties來獲取更高的渲染性能。 舉個例子,opacity屬性是幾個能夠加速的屬性之一,因為GPU可以方便的處理。基本上任何層的透明度漸變瀏覽器都會交給GPU處理來加速。除了opacity能夠使用GPU處理的就是CSS 3D變形了

translateZ() (or translate3d()) Hack

很長一段時間內我們都通過translateZ()或者translate3d() hack來騙取瀏覽器觸發硬件加速,具體做法就是為元素添加沒有變化的3D變形,比如元素在2維空間可以通過添加以下CSS來硬件加速

transform: translate3d(0, 0, 0); 

所謂硬件加速就是創建了一個被傳遞到GPU處理的層的操作,然而強制使用hack方式創建layer並不是長久之計,創建layer的技術可以使頁面加速,但是也有代價:它們占用RAM和GPU存儲空間(考慮到移動設備的存儲容量有限),所以必須唄小心使用,確保這么做真的對頁面渲染有所幫助

為了避免創建layer的hacks,一個允許我們提前通知瀏覽器我們將對元素做何種變化的CSS屬性被引入,這樣瀏覽器可以優化處理元素渲染的方式,為元素提前准備昂貴的動畫處理操作,這就是wiil-change屬性

牛逼的 will-change屬性

will-change屬性可以提前通知瀏覽器我們要對元素做什么動畫,這樣瀏覽器可以提前准備合適的優化設置。這樣可以避免對頁面響應速度有重要影響的昂貴成本。元素可以更快的被改變,渲染的也更快,這樣頁面可以快速更新,表現的更加流暢。

舉個例子,當對於素使用 CSS 3D變形時,元素及其內容可以在合成到頁面之前被創建到我們之前說的layer。然而把元素放到layer中是個昂貴的操作,這將會導致變形動畫延遲一個課件的瞬間,也就是flicker

為了避免這種延時,我們可以在發生之前通知瀏覽器,這樣瀏覽器會有一定的時間去准備這些變化,當發生的時候layer已經准備好了,這樣動畫酒會很流暢,不會閃屏

使用will-change提示瀏覽器關於即將發生的變形十分簡單,添加個CSS屬性就行

will-change: transform; 

也可以告訴瀏覽器要改變元素的滾動條位置,或者多個要變化的屬性,寫下屬性的名字就行,也可以寫多個,逗號隔開

will-change: transform, opacity; 

聲明了元素即將進行的變化會讓瀏覽器在渲染頁面時做更好的決定,這明顯比之前說的3D hacks要好。

合理使用

了解了will-change的行為,為瀏覽器上一切元素設置will-change是不是效率會變高?答案是否定的,will-change如果被濫用會使頁面崩潰。

will-change也有副作用,雖然並不直接可見,畢竟它只是在背后和瀏覽器說悄悄話,為了合理使用will-change,給一些小建議

不要聲明太多屬性或為太多元素聲明

*,
*::before, *::after { will-change: all; } 

雖然看起來很屌,但其實對頁面渲染傷害很大,這樣的規則設了和沒設沒什么區別,瀏覽器本來就嘗試最優的渲染所有元素,就等於你讓老師重點照顧班里每個同學一樣,就是廢話!

其實這甚至是有害的,因為一些操作會占用太多的資源,甚至會導致頁面奔潰,就等於強制要求老師為每個學生補課,累死了。。。

給瀏覽器足夠的時間工作

will-change顧名思義,通知瀏覽器即將發生的變化,而不是正在發生的變化。使用will-change,我們要求瀏覽器重點照顧我們聲明的元素,為了這個瀏覽器需要一定的時間來組織優化操作,這樣當變化發生的時候,優化才能沒有延遲的作用到元素

在變化前立即為元素添加will-change幾乎沒有作用,可能還不如不設置,因為會導致新的layer創建

.element:hover { will-change: transform; transition: transform 2s; transform: rotate(30deg) scale(1.5); } 

這樣的設置就沒什么用,我們需要給瀏覽器足夠的時間,下面這樣就是有用的,感受一下

.element { /* style rules */ transition: transform 1s ease-out; } .element:hover { will-change: transform; } .element:active { transform: rotateY(180deg); } 

如果一定要hover的時候,也有技巧

.element { transition: opacity .3s linear; } /* declare changes on the element when the mouse enters / hovers its ancestor */ .ancestor:hover .element { will-change: opacity; } /* apply change when element is hovered */ .element:hover { opacity: .5; } 

其實核心思想就是讓瀏覽器有時間去准備

變化完成后移除will-change

對於一般的優化,當變化完成的時候瀏覽器會撤銷優化,恢復普通模式,但是如果使用了will-change會導致該優化遲遲不能釋放,這就要求我們用完了就釋放

這時候我們需要借助JavaScript

// Rough generic example // Get the element that is going to be animated on click, for example var el = document.getElementById('element'); // Set will-change when the element is hovered el.addEventListener('mouseenter', hintBrowser); el.addEventListener('animationEnd', removeHint); function hintBrowser() { // The optimizable properties that are going to change // in the animation's keyframes block this.style.willChange = 'transform, opacity'; } function removeHint() { this.style.willChange = 'auto'; } 

當然對於用戶會反復觸發的操作放在style中不移除也可以

will-change屬性的值

  1. auto 表示沒有明確的意圖; 無論是啟發式和最優化,用戶代理應該應用都和正常情況相同
  2. scroll-position 表示開發者期望去在接下來去改變或者有動畫應用元素的滾動位置
  3. contents 表示開發者期望去在接下來去改變或者有動畫應用元素的內容
  4. 用來排除關鍵字 will-change, none, all, auto, scroll-position, and contents, 從之外增加一些通用的關鍵字

    will-change: transform:
    will-change: opacity:
    will-change: top, left, bottom, right:

如果一個屬性無最初的值,在這個元素上這個屬性將創建一個堆棧的內容, 明確規定在will-change的屬性必須在這個元素上創建一個堆棧的內容.

如果一個屬性無最初的值, 這個屬性將造成這個元素產生一個包含區塊的固定定位的元素, 明確規定在 will-change的屬性必須造成這個元素產生一個包含區塊的固定定位的元素

瀏覽器兼容性

這個目前不樂觀,相信以后會好

imageimage

結束語

will-change可以幫助我們擺脫hack的硬件加速,但是能力越大、責任越大

Tab Atkins Jr

Set will-change to the properties you’ll actually change, on the elements that are actually changing. And remove it when they stop.

 

翻譯:http://selayou9527.github.io/2014/11/07/CSS%20will-change%20%E5%B1%9E%E6%80%A7/

原文: CSS will-change 屬性


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM