深入探究CSS中Animations和Transitions的工作原理

在這篇文章中,我們將會(huì)去探究一下瀏覽器是如何去處理CSS Animations和CSS Transitions的,以便使你在寫(xiě)一些動(dòng)畫(huà)效果之前就可以對(duì)該動(dòng)畫(huà)在瀏覽器中運(yùn)行效果有一個(gè)心理預(yù)判。有了這些預(yù)判,你就可以設(shè)計(jì)出一些在瀏覽器中運(yùn)行流暢的動(dòng)畫(huà)效果,從而帶來(lái)更流暢的用戶體驗(yàn)。
瀏覽器的內(nèi)部工作
讓我們了解一些瀏覽器的工作原理,一探究竟。一旦我們了解了瀏覽器是如何工作的,我們就可以更好的去駕馭它。
現(xiàn)代瀏覽器通常擁有兩個(gè)重要的執(zhí)行線程,這兩個(gè)線程相互配合來(lái)渲染出頁(yè)面:
主線程
排版線程
通常情況下,主線程主要負(fù)責(zé)以下工作:
運(yùn)行JavaScript
計(jì)算HTML元素的CSS樣式
布局頁(yè)面
把頁(yè)面元素繪制成一個(gè)或多個(gè)位圖
把這些位圖移交給排版線程
通常情況下,排版線程主要負(fù)責(zé)以下工作:
通過(guò)GPU渲染位圖,并顯示在屏幕上
向主線程請(qǐng)求更新位圖的可見(jiàn)部分或即將可見(jiàn)的部分
判斷出當(dāng)前頁(yè)面處于可見(jiàn)的部分
判斷出即將通過(guò)頁(yè)面滾動(dòng)而可見(jiàn)的部分
隨著用戶滾動(dòng)頁(yè)面來(lái)移動(dòng)這些部分(譯者注:可見(jiàn)部分的和即將可見(jiàn)的部分)
當(dāng)長(zhǎng)時(shí)間運(yùn)行JavaScript或渲染一個(gè)很多的元素時(shí),主線程會(huì)一直處于忙碌狀態(tài)。在這期間它不會(huì)對(duì)用戶的輸入做出任何反應(yīng)。
在另一方面,排版線程對(duì)用戶輸入保持著非??斓捻憫?yīng)。當(dāng)頁(yè)面變化時(shí),排版線程嘗試以每秒60幀的速度去重繪頁(yè)面,即便這時(shí)頁(yè)面還不完整。
舉例來(lái)說(shuō),當(dāng)用戶滾動(dòng)頁(yè)面時(shí),排版線程向主線程請(qǐng)求更新頁(yè)面新顯示部分的位圖,但是,如果此時(shí)主線程并不能迅速響應(yīng)請(qǐng)求,排版線程并不會(huì)去等待響應(yīng),它會(huì)用它目前所擁有的這部分頁(yè)面的內(nèi)容去渲染頁(yè)面,由于對(duì)應(yīng)的內(nèi)容還沒(méi)有,所以會(huì)以白板的形式渲染出來(lái)。
GPU
我前邊提到過(guò)排版線程通過(guò)GPU把位圖繪制到了屏幕上。讓我們快速的過(guò)一下GPU相關(guān)的東西。
GPU是一種芯片,在今天的大多數(shù)手機(jī),平板以及電腦中都能發(fā)現(xiàn)它的身影。它是非常專業(yè)的,這意味著GPU在某些方面非常擅長(zhǎng),但是在另外一些方面去表現(xiàn)不好。
GPU比較擅長(zhǎng)于:
繪制位圖到屏幕
重復(fù)的繪制同一個(gè)位圖
在不同的位置,以不同的旋轉(zhuǎn)角度,或者不同的縮放大小來(lái)繪制同一個(gè)位圖。
GPU相對(duì)慢的地方:
將位圖加載到顯存里。
transition: height
現(xiàn)在我們已經(jīng)在軟件層面和硬件層面對(duì)如何渲染頁(yè)面有了一個(gè)粗略的認(rèn)識(shí)。接下來(lái),讓我們看一下瀏覽器的主線程和排版線程是如何協(xié)同工作來(lái)完成一個(gè)CSS Transition的。
假設(shè)我們想要將一個(gè)元素的高度值從100px轉(zhuǎn)換到200px,如下所示:
- div {
- height: 100px;
- transition: height 1s linear;
- }
- div:hover {
- height: 200px;
- }
主線程和排版線程會(huì)根據(jù)下圖所示時(shí)序圖來(lái)完成這個(gè)Transition。注意:在橙色方框中的操作是潛在的耗時(shí)操作,藍(lán)色方框中的操作是較快的操作。
正如你所見(jiàn),整個(gè)過(guò)程有很多橙色的方框,意味著瀏覽器有相當(dāng)繁重的工作要處理,也意味著這個(gè)Transition可能會(huì)出現(xiàn)卡頓。
在整個(gè)Transition的每一幀中,瀏覽器都要去重新布局,繪制頁(yè)面,并把最新的位圖對(duì)象加載到GPU。我們前邊了解過(guò),把位圖對(duì)象加載到GPU的內(nèi)存中是個(gè)相對(duì)緩慢的操作。
瀏覽器之所以要在每一幀動(dòng)畫(huà)上處理如此繁重的工作是因?yàn)檫@個(gè)元素的內(nèi)容一直在變化。修改一個(gè)元素的高度可能會(huì)引起其子元素也要相應(yīng)的改變大小,因此瀏覽器必須去重新布局。重新布局后,主線程必須為該元素重新生成位圖對(duì)象。
transition: transform
由此可見(jiàn),對(duì)高度進(jìn)行的Transition相對(duì)來(lái)說(shuō)性能比較差,那有一些性能比較好的Transition嗎?
假設(shè)我們想要把一個(gè)元素從一半大小縮放到實(shí)際大小,并假設(shè)我們使用CSS的transform 屬性來(lái)對(duì)它進(jìn)行縮放,同時(shí)使用CSS的transition屬性來(lái)生成縮放的動(dòng)畫(huà)效果,如下所示:
- div {
- transform: scale(0.5);
- transition: transform 1s linear;
- }
- div:hover {
- transform: scale(1.0);
- }
讓我們看下一下這個(gè)例子的時(shí)序圖:
我們看到只有很少的幾個(gè)橙色的方框,意味著這個(gè)動(dòng)畫(huà)效果可能會(huì)很流暢!那么,一個(gè)元素的transform動(dòng)畫(huà)效果與其高度的動(dòng)畫(huà)效果有什么不同呢?
根據(jù)定義,CSS的transform屬性不會(huì)改變?cè)氐牟季?,也不?huì)影響到其周圍的元素。它把元素當(dāng)做一個(gè)整體看待——縮放整個(gè)元素、旋轉(zhuǎn)整個(gè)元素或者移動(dòng)整個(gè)元素。
這對(duì)瀏覽器來(lái)說(shuō)是一個(gè)好消息!瀏覽器只需在動(dòng)畫(huà)開(kāi)始的時(shí)候生成這個(gè)元素的位圖對(duì)象,并把它傳遞給GPU。在這之后,瀏覽器無(wú)需再做任何重新布局,繪制頁(yè)面以及傳遞位圖對(duì)象的操作了,相反,瀏覽器可以利用GPU擅長(zhǎng)的繪制的特點(diǎn)來(lái)快速的在不同的位置,旋轉(zhuǎn)或縮放同一個(gè)位圖對(duì)象。
設(shè)計(jì)決策
那么,是否這就意味這我們不要去緩動(dòng)一個(gè)元素的高度?非也,一些情況下,這是你的設(shè)計(jì)效果的一部分,并且動(dòng)畫(huà)效果可以非??斓耐瓿?。也許動(dòng)畫(huà)的元素是孤立的,不會(huì)引起頁(yè)面其他部分進(jìn)行重新布局;也許該元素只是單純的進(jìn)行重繪,瀏覽器可以快速的完成;也許該元素很小,瀏覽器只需將很小的位圖對(duì)象傳遞給GPU。
當(dāng)然了,在不影響你設(shè)計(jì)的視覺(jué)效果的情況下,最好去緩動(dòng)一個(gè)性能較好的CSS屬性,如transform,而不是去緩動(dòng)一個(gè)性能較差的CSS屬性,如height。舉例來(lái)說(shuō),假設(shè)你的設(shè)計(jì)中有一個(gè)按鈕,當(dāng)點(diǎn)擊它的時(shí)候會(huì)出來(lái)一個(gè)菜單,試著去緩動(dòng)菜單的transform屬性來(lái)顯示它而不是緩動(dòng)它的top或height屬性來(lái)達(dá)到類似的效果。
在動(dòng)畫(huà)上特別快的CSS屬性包括:
CSS transform
CSS opacity
CSS filter (依賴于過(guò)濾器的復(fù)雜度和瀏覽器)
目前這個(gè)列表是非常有限的,但是隨著瀏覽器的進(jìn)步,你將會(huì)看到越來(lái)越多的CSS屬性在動(dòng)畫(huà)中變得越來(lái)越快。另外,不要輕視當(dāng)前的列表。你可能會(huì)很驚訝你能通過(guò)組合這些屬性創(chuàng)造出許多豐富的效果。只要有創(chuàng)意!
相關(guān)文章
使用CSS transition和animation改變漸變狀態(tài)的實(shí)現(xiàn)方法
CSS漸變特性對(duì)于我們的幫助已經(jīng)非常強(qiáng)大了,它們可以幫助我們繪圖、 創(chuàng)建圖片占位符 、制作環(huán)形進(jìn)度條等等。接下來(lái)通過(guò)本文給大家介紹使用CSS transition和animation改變漸2018-10-29CSS3與動(dòng)畫(huà)有關(guān)的屬性transition、animation、transform對(duì)比(史上最全
這篇文章主要介紹了CSS3與動(dòng)畫(huà)有關(guān)的屬性transition、animation、transform對(duì)比,通過(guò)瀏覽器兼容性,用法和對(duì)比更深刻的展示了彼此之間的異同,具體操作步驟大家可查看下文2017-08-18CSS3中動(dòng)畫(huà)屬性transform、transition和animation屬性的區(qū)別
最近在項(xiàng)目中用到了CSS3中的動(dòng)畫(huà)屬性。無(wú)奈對(duì)于css3幾個(gè)新加的屬性不太熟悉,常常容易搞混。所以從網(wǎng)站研究了點(diǎn)資料,總結(jié)一下,方便有需要的朋友們可以參考學(xué)習(xí)。2016-09-25CSS3中的Transition過(guò)度與Animation動(dòng)畫(huà)屬性使用要點(diǎn)
這篇文章主要介紹了CSS3中的Transition過(guò)度與Animation動(dòng)畫(huà)屬性使用要點(diǎn)Transition和Animation能被用來(lái)制作基本的頁(yè)面圖片動(dòng)態(tài)效果,當(dāng)然進(jìn)一步的控制還是需要JavaScript的2016-05-20CSS3的transition和animation的用法實(shí)例介紹
transition用于設(shè)定一個(gè)元素的兩個(gè)狀態(tài),不同的狀態(tài)可以用偽類,下面與大家分享下CSS3的transition和animation的用法,需要的朋友可以參考下2014-08-20