摘要:在樣式代碼添加錄制性能日志如下可見,已經(jīng)不存在繪制的步驟了。下面通過一段代碼模擬頁面進(jìn)入的過程,來演示這個問題運(yùn)行效果如下可以看到,固定定位的黃色元素是在動畫結(jié)束后才突然出現(xiàn)的。
對于移動端的Web單頁應(yīng)用來說,為了達(dá)到媲美原生應(yīng)用的效果,頁面過渡動畫是必不可少的。常用的頁面過渡動畫包括:
位移——當(dāng)前頁向左側(cè)或右側(cè)水平移出可視區(qū),下一頁由反方向移入可視區(qū)。
不透明度變化——當(dāng)前頁淡出,下一頁淡入。
1和2同時進(jìn)行。
(注意:以下討論和實(shí)驗(yàn)均在 Chrome 68 瀏覽器環(huán)境下進(jìn)行)
目前大多數(shù)設(shè)備的屏幕刷新率為60次/秒,算下來每個幀的預(yù)算時間約為16.66毫秒(1/60秒)。考慮到瀏覽器還有其他工作要執(zhí)行,實(shí)際上預(yù)算時間只有10毫秒。跟此預(yù)算時間的差值越大,用戶就會覺得動畫過程越卡。那么,在這10毫秒內(nèi)要完成什么事情呢?當(dāng)使用JavaScript實(shí)現(xiàn)視覺交互效果時,一般要經(jīng)過以下流程:
JavaScript的執(zhí)行。例如修改元素的樣式,或者給元素添加/刪除樣式類。
樣式計(jì)算。根據(jù)樣式規(guī)則計(jì)算出元素的最終樣式。
布局(layout)。根據(jù)上一步的結(jié)果,計(jì)算元素占據(jù)的空間大小及其在屏幕的位置。注意,一個元素布局上的變化有可能會引發(fā)其他元素的聯(lián)動變化。
繪制(paint)。填充像素的過程,包括元素的每個可視部分。一般來說,繪制是在多個層上進(jìn)行的。
合成(composite)。把各層按正確順序合并成一個層,顯示到屏幕上。
值得注意的是,并非每一幀都會經(jīng)過上述每一個步驟的處理。如果元素的幾何屬性(尺寸、位置)沒有變化,就不需要進(jìn)行布局;如果連元素的外觀都沒有改變,就不需要繪制。所以,實(shí)現(xiàn)流暢動畫的關(guān)鍵就在于如何減少布局和繪制。
位移對于位移動畫來說,最直接的實(shí)現(xiàn)方式,就是把元素設(shè)成絕對定位,然后去改變它的left樣式值。例如:
使用Chrome開發(fā)者工具中的Performance面板錄制動畫過程的性能日志,如下圖所示:
可見,元素在移動的過程中不斷觸發(fā)了布局和繪制。所以,這種實(shí)現(xiàn)方式的性能是極低的。網(wǎng)上諸多文獻(xiàn)會推薦以transform的變化代替left的變化,而實(shí)際情況又是怎么樣呢?把樣式代碼稍作修改:
.page { position: absolute; left: 0; top: 0; width: 100%; min-height: 100%; background: #ffffd; transition-duration: 2s; transition-property: transform; } .leave { transform: translateX(-100%); }
錄制性能日志如下圖所示:
可見,僅僅是在動畫開始和結(jié)束兩個時間點(diǎn)觸發(fā)了繪制,而布局則完全沒有觸發(fā)。這樣一來,性能就有了很大的提升。但是,這里還有兩個疑問:
為什么transform動畫過程沒有觸發(fā)布局和繪制?
為什么動畫開始前觸發(fā)了兩次繪制,動畫結(jié)束之后觸發(fā)了一次繪制?
要回答這兩個問題,就得了解合成層。
合成層當(dāng)滿足某些條件的時候,元素在渲染時會被分配到一個獨(dú)立的層中進(jìn)行渲染,只要該層的內(nèi)容不發(fā)生改變,就不會觸發(fā)繪制,瀏覽器會直接通過合成形成一個新的幀。常見的提升為合成層的條件包括:
對opacity或transform應(yīng)用了animation或transition;
有 3D transform ;
will-change設(shè)置為opacity或transform。
很明顯,上一節(jié)的transform位移動畫滿足了第一個條件。所以整個動畫的渲染過程是這樣的:
動畫開始時,由于div.page被提升為獨(dú)立的合成層,所以它要重新繪制;而document所在層相當(dāng)于少了一塊內(nèi)容,也得重新繪制;
動畫過程中,div.page沒有其他變化,所以不觸發(fā)布局和繪制;
動畫結(jié)束后,div.page不再是獨(dú)立的合成層,回到了document所在層,所以document又重新繪制了一遍。
如果讓div.page一直在獨(dú)立的合成層中渲染,則可以省掉上述過程中繪制的環(huán)節(jié)。在樣式代碼添加「will-change: transform」:
.page { position: absolute; left: 0; top: 0; width: 100%; min-height: 100%; background: #ffffd; transition-duration: 2s; transition-property: transform; will-change: transform; }
錄制性能日志如下:
可見,已經(jīng)不存在繪制的步驟了。
順帶一提,Chrome開發(fā)者工具中有一個Layers面板,可以方便地查看頁面上合成層以及成為合成層的原因。
(注意:由于低版本瀏覽器不支持will-change,所以實(shí)際應(yīng)用中,如果想把元素提升到獨(dú)立的合成層中渲染,可以用「transform: translateZ(0)」)
不透明度眾所周知,不透明度就是通過opacity樣式來控制的。那么opacity的變化是否會觸發(fā)布局和繪制呢?把樣式代碼修改如下:
.page { position: absolute; left: 0; top: 0; width: 100%; min-height: 100%; background: #ffffd; transition-duration: 2s; transition-property: opacity; } .leave { opacity: 0; }
錄制性能日志如下圖所示:
在常規(guī)認(rèn)知中,opacity的變化并不會導(dǎo)致元素位置和尺寸的變化,理應(yīng)不會觸發(fā)布局。但上述過程中確實(shí)觸發(fā)了一次布局,表現(xiàn)較為詭異。接下來給div.page添加「will-change: opacity」使其一直在獨(dú)立的合成層中渲染。錄制性能日志如下:
可見,還是會觸發(fā)一次繪制。而針對這「一次的布局」和「一次的繪制」,我進(jìn)行了進(jìn)一步的實(shí)驗(yàn),得出的結(jié)論是:opacity從1(包括未設(shè)置的情況,下同)變更到小于1,以及從小于1變更到1,都會觸發(fā)布局和繪制;即使在獨(dú)立的合成層中渲染,也只能省掉布局,無法省掉繪制。
由于在opacity動畫過程中從1到小于1的變更只會有一次,所以上述的布局和繪制都只觸發(fā)一次。
位移和不透明度同時使用兩種動畫,修改樣式代碼如下:
.page { position: absolute; left: 0; top: 0; width: 100%; min-height: 100%; background: #ffffd; transition-duration: 2s; transition-property: transform, opacity; } .leave { transform: translateX(-100%); opacity: 0; }
按照前文的描述,動畫過程會觸發(fā):
一次布局,在動畫開始時觸發(fā),由opacity引起;
兩次繪制,在動畫開始時觸發(fā),因opacity以及提升為獨(dú)立合成層引起;
由獨(dú)立合成層回到document所在層時引起。
倘若加上「will-change: transform, opacity」,使div.page一直在獨(dú)立的合成層中渲染,則只觸發(fā)一次繪制,由opacity引起。
然而,創(chuàng)建一個新的合成層并不是免費(fèi)的,它會導(dǎo)致額外的內(nèi)存開銷。在單頁應(yīng)用中,應(yīng)用頁面過渡動畫的元素是頁面的最外層容器,包含了該頁面所有內(nèi)容結(jié)構(gòu)。如果讓其長期在獨(dú)立的合成層中渲染,那內(nèi)存的消耗是非常大的。
所以,可以僅在動畫過程中讓其在獨(dú)立的合成層中渲染,而在其他情況下則維持常規(guī)狀態(tài)。
transform和fixed的沖突如果用transform實(shí)現(xiàn)頁面過渡動畫,想必大家都遇到過一個問題:頁面上固定定位的元素,其位置變得不太正常了。
下面通過一段代碼模擬頁面進(jìn)入的過程,來演示這個問題:
運(yùn)行效果如下:
可以看到,固定定位的黃色元素是在動畫結(jié)束后才突然出現(xiàn)的。那在這之前它跑到哪去了呢?
如果給一個固定定位元素的任意一個祖先元素設(shè)置樣式「transform」或者「will-change: transform」,那么該元素就會相對于最近的設(shè)置了上述樣式的祖先元素定位。
因?yàn)閐iv.page的高度設(shè)成了150%,所以,在動畫過程中,黃色元素實(shí)際上是跑到了頁面的最底下(超出了瀏覽器可視范圍)去了。而在某些比較舊(如 iOS 9 的Safari)的移動端瀏覽器中,問題更為嚴(yán)重,固定定位的元素可能會消失掉再也不出現(xiàn)。
網(wǎng)上能查到的解決方案有兩種:
通過絕對定位模擬固定定位。雖然是可行的,但是在移動端瀏覽器內(nèi),交互上會有一些細(xì)節(jié)問題,而且元素內(nèi)部的滾動很容易與頁面滾動沖突。
把固定定位的元素放到應(yīng)用transform動畫的元素外。但這對使用「Vue.js」這類框架開發(fā)的單頁應(yīng)用來說可行性較低,因?yàn)樵谶@類框架中,一個頁面就是一個組件,多帶帶把頁面中的某個元素抽離出來是比較麻煩的。
所以,這里介紹第三種方案——在頁面過渡動畫結(jié)束之后(此時transform樣式已被移除,不再影響fixed),再讓固定定位的元素插入到頁面容器。并且,為了讓它的出現(xiàn)顯得不那么突然,增加緩動動畫。代碼主要修改點(diǎn)如下:
@keyframes kf-move-in { 0% { transform: translateY(100%); } 100% { transform: translateY(0); } } .move-in { animation-name: kf-move-in; animation-duration: 0.45s; }
運(yùn)行效果如下:
這樣一來,整個交互就較為友好了。這同時也說明:技術(shù)上的問題,不一定只能通過技術(shù)去解決,也可以從交互上去尋求解決方案。
參考文獻(xiàn)《渲染性能》
《堅(jiān)持僅合成器的屬性和管理層計(jì)數(shù)》
《無線性能優(yōu)化:Composite》
本文同時發(fā)布于作者個人博客: https://mrluo.life/article/de...
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/99493.html
摘要:在樣式代碼添加錄制性能日志如下可見,已經(jīng)不存在繪制的步驟了。下面通過一段代碼模擬頁面進(jìn)入的過程,來演示這個問題運(yùn)行效果如下可以看到,固定定位的黃色元素是在動畫結(jié)束后才突然出現(xiàn)的。 對于移動端的Web單頁應(yīng)用來說,為了達(dá)到媲美原生應(yīng)用的效果,頁面過渡動畫是必不可少的。常用的頁面過渡動畫包括: 位移——當(dāng)前頁向左側(cè)或右側(cè)水平移出可視區(qū),下一頁由反方向移入可視區(qū)。 不透明度變化——當(dāng)前頁淡...
摘要:在的發(fā)展過程中,是最早與之父合作的人之一。問您認(rèn)為中國的開發(fā)者雖然起步晚,但是現(xiàn)在已經(jīng)趕上了是的。但是我知道,它們只是進(jìn)化的一部分。第一個最主要的原因就是要保護(hù)。 非商業(yè)轉(zhuǎn)載請注明作譯者、出處,并保留本文的原始鏈接:http://www.ituring.com.cn/article/194473 Bert Bos是一位計(jì)算機(jī)科學(xué)家,他也是CSS的創(chuàng)始人之一。在CSS的發(fā)展過程...
摘要:春招結(jié)果五月份了,春招已經(jīng)接近尾聲,因?yàn)榈搅酥芪逋砩蟿偤糜锌眨院唵蔚赜涗浺幌伦约旱拇赫羞^程。我的春招從二月初一直持續(xù)到四月底,截止今天,已經(jīng)斬獲唯品會電商前端研發(fā)部大數(shù)據(jù)與威脅分析事業(yè)部京東精銳暑假實(shí)習(xí)生的騰訊的是早上打過來的。 春招結(jié)果 五月份了,春招已經(jīng)接近尾聲,因?yàn)榈搅酥芪逋砩蟿偤糜锌眨院唵蔚赜涗浺幌伦约旱拇赫羞^程。我的春招從二月初一直持續(xù)到四月底,截止今天,已經(jīng)斬獲唯品...
摘要:下面具體說一說四次面試經(jīng)歷,已經(jīng)問到的問題,現(xiàn)在就做一次總結(jié)。第四次面試第四家公司真的就是高大上了,在騰訊的旁邊,先不說面試,先說騰訊,真的就是當(dāng)時內(nèi)心挺害怕的。有點(diǎn)不好意思的說就是當(dāng)時站在騰訊大樓面前腿是有些瑟瑟發(fā)抖的。 前言 做一個自我介紹,本人男,愛好女。曾以為自己可以改變世界,沒想到被世界無情的摧殘。來深圳之前那種找工作少于 1W 少跟我談,變成了收到 offer 了 4000...
閱讀 953·2021-11-24 09:39
閱讀 2689·2021-09-26 09:55
閱讀 14154·2021-08-23 09:47
閱讀 3577·2019-08-30 15:52
閱讀 849·2019-08-29 13:49
閱讀 997·2019-08-23 18:00
閱讀 844·2019-08-23 16:42
閱讀 1635·2019-08-23 14:28