日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

瀏覽器極致性能調(diào)優(yōu)之——瀏覽器合成與渲染層優(yōu)化

 西北望msm66g9f 2020-05-06

一個(gè) CSS 屬性引發(fā)的血案

Web 頁(yè)面性能是前端開(kāi)發(fā)特別需要關(guān)注的重點(diǎn),評(píng)判前端 Web 頁(yè)面性能的指標(biāo)有很多,頁(yè)面的流暢度是其中的一種,如何讓頁(yè)面變得 “柔順絲滑”,要討論起來(lái)可就是個(gè)相當(dāng)有料的話題了。之前開(kāi)發(fā)移動(dòng)端 H5 頁(yè)面的時(shí)候,就遇到過(guò)一個(gè)有趣的性能問(wèn)題 —— 某個(gè)賣(mài)場(chǎng)頁(yè)面在 IOS 手機(jī)上出現(xiàn)了嚴(yán)重的卡頓,但在安卓機(jī)型下卻表現(xiàn)得十分流暢。歸納一下在 iPhoneX 上測(cè)試的具體表現(xiàn):

  • 頁(yè)面加載時(shí)存在明顯的延遲,但通過(guò)代理抓到的網(wǎng)絡(luò)請(qǐng)求耗時(shí)并不比 Android 的高;

  • 頁(yè)面滾動(dòng)時(shí)會(huì)出現(xiàn)短暫的局部白屏,即丟幀。

根據(jù)這些表征情況不難推斷出,應(yīng)該是有什么東西在瘋狂占用 CPU,卡住了渲染進(jìn)程。

然而具體是什么東西,要問(wèn)我我也并不知道。對(duì)于這種沒(méi)法通過(guò)斷點(diǎn)定位到的問(wèn)題,恐怕只有用上祖師爺親傳的 “代碼二分法” 才能制服得了了。一番艱苦排查之后,問(wèn)題的根源終于聚焦到了下邊這行 CSS 代碼上:

filter: blur(100px);

這行 CSS 代碼用于實(shí)現(xiàn)一個(gè)高斯模糊,來(lái)構(gòu)造一個(gè)優(yōu)惠券模塊的底部陰影。由于活動(dòng)配置了多個(gè)優(yōu)惠券,導(dǎo)致頁(yè)面里存在多個(gè)設(shè)置了這個(gè)屬性的 div 元素,而 IOS 手機(jī)的瀏覽器似乎對(duì)這個(gè)屬性的渲染十分吃力(然而為何吃力的原因不得而知),進(jìn)而導(dǎo)致渲染進(jìn)程的 CPU 占用率過(guò)高,最終造成卡頓。

哦?CPU 忙不過(guò)來(lái)了?好辦嘛!我給優(yōu)惠券模塊又加了這樣一行代碼,然后問(wèn)題迎刃而解 ......

  will-change: transform;

你沒(méi)看錯(cuò),我也沒(méi)寫(xiě)少,確實(shí)就是靠一行代碼解決的。

認(rèn)識(shí)它的人可能已經(jīng)看出來(lái)了,大致原理其實(shí)很簡(jiǎn)單,這行代碼能夠開(kāi)啟 GPU 加速頁(yè)面渲染,從而大大降低了 CPU 的負(fù)載壓力,達(dá)到優(yōu)化頁(yè)面渲染性能的目的,不了解 CSS 硬件加速的可以看看這篇文章 Increase Your Site’s Performance with Hardware-Accelerated CSS[1]

問(wèn)題解決了,但是真的就這么完事了嗎?本著 “拔樹(shù)尋根” 的偉大原則,我把這個(gè)東西好好地研究了一番,才發(fā)現(xiàn) GPU 加速其實(shí)沒(méi)那么簡(jiǎn)單。

瀏覽器渲染流程

在具體討論原理之前,我們需要了解一下瀏覽器渲染流程的一些基本概念。瀏覽器渲染流程是個(gè)老生常談的話題了,對(duì)于 “瀏覽器如何呈現(xiàn)一個(gè)頁(yè)面的內(nèi)容” 的這類問(wèn)題,不少人都可以講出一個(gè)相對(duì)完整的過(guò)程,從網(wǎng)絡(luò)請(qǐng)求到瀏覽器解析,可以具體到很多的細(xì)節(jié)。除去網(wǎng)絡(luò)資源獲取的步驟,我們理解的 Web 頁(yè)面的展示,一般可以分為 構(gòu)建 DOM 樹(shù)構(gòu)建渲染樹(shù)、布局、繪制、渲染層合成 幾個(gè)步驟。

  • 構(gòu)建 DOM 樹(shù):瀏覽器將 HTML 解析成樹(shù)形結(jié)構(gòu)的 DOM 樹(shù),一般來(lái)說(shuō),這個(gè)過(guò)程發(fā)生在頁(yè)面初次加載,或頁(yè)面 JavaScript 修改了節(jié)點(diǎn)結(jié)構(gòu)的時(shí)候。

  • 構(gòu)建渲染樹(shù):瀏覽器將 CSS 解析成樹(shù)形結(jié)構(gòu)的 CSSOM 樹(shù),再和 DOM 樹(shù)合并成渲染樹(shù)。

  • 布局(Layout):瀏覽器根據(jù)渲染樹(shù)所體現(xiàn)的節(jié)點(diǎn)、各個(gè)節(jié)點(diǎn)的 CSS 定義以及它們的從屬關(guān)系,計(jì)算出每個(gè)節(jié)點(diǎn)在屏幕中的位置。Web 頁(yè)面中元素的布局是相對(duì)的,在頁(yè)面元素位置、大小發(fā)生變化,往往會(huì)導(dǎo)致其他節(jié)點(diǎn)聯(lián)動(dòng),需要重新計(jì)算布局,這時(shí)候的布局過(guò)程一般被稱為回流(Reflow)。

  • 繪制(Paint):遍歷渲染樹(shù),調(diào)用渲染器的 paint() 方法在屏幕上繪制出節(jié)點(diǎn)內(nèi)容,本質(zhì)上是一個(gè)像素填充的過(guò)程。這個(gè)過(guò)程也出現(xiàn)于回流或一些不影響布局的 CSS 修改引起的屏幕局部重畫(huà),這時(shí)候它被稱為重繪(Repaint)。實(shí)際上,繪制過(guò)程是在多個(gè)層上完成的,這些層我們稱為渲染層(RenderLayer)。

  • 渲染層合成(Composite):多個(gè)繪制后的渲染層按照恰當(dāng)?shù)闹丿B順序進(jìn)行合并,而后生成位圖,最終通過(guò)顯卡展示到屏幕上。

這是一個(gè)基本的瀏覽器從解析到繪制一個(gè) Web 頁(yè)面的過(guò)程,跟上邊頁(yè)面卡頓問(wèn)題的解決方法相關(guān)的,主要是最后一個(gè)環(huán)節(jié) —— 渲染層合成。

渲染層合成

一、什么是渲染層合成

在 DOM 樹(shù)中每個(gè)節(jié)點(diǎn)都會(huì)對(duì)應(yīng)一個(gè)渲染對(duì)象(RenderObject),當(dāng)它們的渲染對(duì)象處于相同的坐標(biāo)空間(z 軸空間)時(shí),就會(huì)形成一個(gè) RenderLayers,也就是渲染層。渲染層將保證頁(yè)面元素以正確的順序堆疊,這時(shí)候就會(huì)出現(xiàn)層合成(composite),從而正確處理透明元素和重疊元素的顯示。

這個(gè)模型類似于 Photoshop 的圖層模型,在 Photoshop 中,每個(gè)設(shè)計(jì)元素都是一個(gè)獨(dú)立的圖層,多個(gè)圖層以恰當(dāng)?shù)捻樞蛟?z 軸空間上疊加,最終構(gòu)成一個(gè)完整的設(shè)計(jì)圖。

對(duì)于有位置重疊的元素的頁(yè)面,這個(gè)過(guò)程尤其重要,因?yàn)橐坏﹫D層的合并順序出錯(cuò),將會(huì)導(dǎo)致元素顯示異常。

二、瀏覽器的渲染原理

從瀏覽器的渲染過(guò)程中我們知道,頁(yè)面 HTML 會(huì)被解析成 DOM 樹(shù),每個(gè) HTML 元素對(duì)應(yīng)了樹(shù)結(jié)構(gòu)上的一個(gè) node 節(jié)點(diǎn)。而從 DOM 樹(shù)轉(zhuǎn)化到一個(gè)個(gè)的渲染層,并最終執(zhí)行合并、繪制的過(guò)程,中間其實(shí)還存在一些過(guò)渡的數(shù)據(jù)結(jié)構(gòu),它們記錄了 DOM 樹(shù)到屏幕圖形的轉(zhuǎn)化原理,其本質(zhì)也就是樹(shù)結(jié)構(gòu)到層結(jié)構(gòu)的演化。

1、渲染對(duì)象(RenderObject)

一個(gè) DOM 節(jié)點(diǎn)對(duì)應(yīng)了一個(gè)渲染對(duì)象,渲染對(duì)象依然維持著 DOM 樹(shù)的樹(shù)形結(jié)構(gòu)。一個(gè)渲染對(duì)象知道如何繪制一個(gè) DOM 節(jié)點(diǎn)的內(nèi)容,它通過(guò)向一個(gè)繪圖上下文(GraphicsContext)發(fā)出必要的繪制調(diào)用來(lái)繪制 DOM 節(jié)點(diǎn)。

2、渲染層(RenderLayer)

這是瀏覽器渲染期間構(gòu)建的第一個(gè)層模型,處于相同坐標(biāo)空間(z 軸空間)的渲染對(duì)象,都將歸并到同一個(gè)渲染層中,因此根據(jù)層疊上下文,不同坐標(biāo)空間的的渲染對(duì)象將形成多個(gè)渲染層,以體現(xiàn)它們的層疊關(guān)系。所以,對(duì)于滿足形成層疊上下文條件的渲染對(duì)象,瀏覽器會(huì)自動(dòng)為其創(chuàng)建新的渲染層。能夠?qū)е聻g覽器為其創(chuàng)建新的渲染層的,包括以下幾類常見(jiàn)的情況:

  • 根元素 document

  • 有明確的定位屬性(relative、fixed、sticky、absolute)

  • opacity < 1

  • 有 CSS fliter 屬性

  • 有 CSS mask 屬性

  • 有 CSS mix-blend-mode 屬性且值不為 normal

  • 有 CSS transform 屬性且值不為 none

  • backface-visibility 屬性為 hidden

  • 有 CSS reflection 屬性

  • 有 CSS column-count 屬性且值不為 auto 或者有 CSS column-width 屬性且值不為 auto

  • 當(dāng)前有對(duì)于 opacity、transform、fliter、backdrop-filter 應(yīng)用動(dòng)畫(huà)

  • overflow 不為 visible

DOM 節(jié)點(diǎn)和渲染對(duì)象是一一對(duì)應(yīng)的,滿足以上條件的渲染對(duì)象就能擁有獨(dú)立的渲染層。當(dāng)然這里的獨(dú)立是不完全準(zhǔn)確的,并不代表著它們完全獨(dú)享了渲染層,由于不滿足上述條件的渲染對(duì)象將會(huì)與其第一個(gè)擁有渲染層的父元素共用同一個(gè)渲染層,因此實(shí)際上,這些渲染對(duì)象會(huì)與它的部分子元素共用這個(gè)渲染層。

3、圖形層(GraphicsLayer)

GraphicsLayer 其實(shí)是一個(gè)負(fù)責(zé)生成最終準(zhǔn)備呈現(xiàn)的內(nèi)容圖形的層模型,它擁有一個(gè)圖形上下文(GraphicsContext),GraphicsContext 會(huì)負(fù)責(zé)輸出該層的位圖。存儲(chǔ)在共享內(nèi)存中的位圖將作為紋理上傳到 GPU,最后由 GPU 將多個(gè)位圖進(jìn)行合成,然后繪制到屏幕上,此時(shí),我們的頁(yè)面也就展現(xiàn)到了屏幕上。

所以 GraphicsLayer 是一個(gè)重要的渲染載體和工具,但它并不直接處理渲染層,而是處理合成層。

4、合成層(CompositingLayer)

滿足某些特殊條件的渲染層,會(huì)被瀏覽器自動(dòng)提升為合成層。合成層擁有單獨(dú)的 GraphicsLayer,而其他不是合成層的渲染層,則和其第一個(gè)擁有 GraphicsLayer 的父層共用一個(gè)。

那么一個(gè)渲染層滿足哪些特殊條件時(shí),才能被提升為合成層呢?這里列舉了一些常見(jiàn)的情況:

  • 3D transforms:translate3d、translateZ 等

  • video、canvas、iframe 等元素

  • 通過(guò) Element.animate() 實(shí)現(xiàn)的 opacity 動(dòng)畫(huà)轉(zhuǎn)換

  • 通過(guò) СSS 動(dòng)畫(huà)實(shí)現(xiàn)的 opacity 動(dòng)畫(huà)轉(zhuǎn)換

  • position: fixed

  • 具有 will-change 屬性

  • 對(duì) opacity、transform、fliter、backdropfilter 應(yīng)用了 animation 或者 transition

因此,文首例子的解決方案,其實(shí)就是利用 will-change 屬性,將 CPU 消耗高的渲染元素提升為一個(gè)新的合成層,才能開(kāi)啟 GPU 加速的,因此你也可以使用 transform: translateZ(0) 來(lái)解決這個(gè)問(wèn)題。

這里值得注意的是,不少人會(huì)將這些合成層的條件和渲染層產(chǎn)生的條件混淆,這兩種條件發(fā)生在兩個(gè)不同的層處理環(huán)節(jié),是完全不一樣的。

另外,有些文章會(huì)把 CSS Filter 也列為影響 Composite 的因素之一,然而我驗(yàn)證后發(fā)現(xiàn)并沒(méi)有效果。

三、隱式合成

上邊提到,滿足某些顯性的特殊條件時(shí),渲染層會(huì)被瀏覽器提升為合成層。除此之外,在瀏覽器的 Composite 階段,還存在一種隱式合成,部分渲染層在一些特定場(chǎng)景下,會(huì)被默認(rèn)提升為合成層。

對(duì)于隱式合成,CSS GPU Animation[2] 中是這么描述的:

This is called implicit compositing: One or more non-composited elements that should appear above a composited one in the stacking order are promoted to composite layers.(一個(gè)或多個(gè)非合成元素應(yīng)出現(xiàn)在堆疊順序上的合成元素之上,被提升到合成層。)

這句話可能不好理解,它其實(shí)是在描述一個(gè)交疊問(wèn)題(overlap)。舉個(gè)例子說(shuō)明一下:

  • 兩個(gè) absolute 定位的 div 在屏幕上交疊了,根據(jù) z-index 的關(guān)系,其中一個(gè) div 就會(huì)”蓋在“了另外一個(gè)上邊。

  • 這個(gè)時(shí)候,如果處于下方的 div 被加上了 CSS 屬性:transform: translateZ(0),就會(huì)被瀏覽器提升為合成層。提升后的合成層位于 Document 上方,假如沒(méi)有隱式合成,原本應(yīng)該處于上方的 div 就依然還是跟 Document 共用一個(gè) GraphicsLayer,層級(jí)反而降了,就出現(xiàn)了元素交疊關(guān)系錯(cuò)亂的問(wèn)題。

  • 所以為了糾正錯(cuò)誤的交疊順序,瀏覽器必須讓原本應(yīng)該”蓋在“它上邊的渲染層也同時(shí)提升為合成層。

四、層爆炸和層壓縮

1、層爆炸

從上邊的研究中我們可以發(fā)現(xiàn),一些產(chǎn)生合成層的原因太過(guò)于隱蔽了,尤其是隱式合成。在平時(shí)的開(kāi)發(fā)過(guò)程中,我們很少會(huì)去關(guān)注層合成的問(wèn)題,很容易就產(chǎn)生一些不在預(yù)期范圍內(nèi)的合成層,當(dāng)這些不符合預(yù)期的合成層達(dá)到一定量級(jí)時(shí),就會(huì)變成層爆炸。

層爆炸會(huì)占用 GPU 和大量的內(nèi)存資源,嚴(yán)重?fù)p耗頁(yè)面性能,因此盲目地使用 GPU 加速,結(jié)果有可能會(huì)是適得其反。CSS3 硬件加速也有坑[3] 這篇文章提供了一個(gè)很有趣的 DEMO[4],這個(gè) DEMO 頁(yè)面中包含了一個(gè) h1 標(biāo)題,它對(duì) transform 應(yīng)用了 animation 動(dòng)畫(huà),進(jìn)而導(dǎo)致被放到了合成層中渲染。由于 animation transform 的特殊性(動(dòng)態(tài)交疊不確定),隱式合成在不需要交疊的情況下也能發(fā)生,就導(dǎo)致了頁(yè)面中所有 z-index 高于它的節(jié)點(diǎn)所對(duì)應(yīng)的渲染層全部提升為合成層,最終讓這個(gè)頁(yè)面整整產(chǎn)生了幾千個(gè)合成層。

消除隱式合成就是要消除元素交疊,拿這個(gè) DEMO 來(lái)說(shuō),我們只需要給 h1 標(biāo)題的 z-index 屬性設(shè)置一個(gè)較高的數(shù)值,就能讓它高于頁(yè)面中其他元素,自然也就沒(méi)有合成層提升的必要了。點(diǎn)擊 DEMO 中的復(fù)選按鈕就可以給 h1 標(biāo)題加上一個(gè)較大的 z-index,前后效果對(duì)比十分明顯。

2、層壓縮

當(dāng)然了,面對(duì)這種問(wèn)題,瀏覽器也有相應(yīng)的應(yīng)對(duì)策略,如果多個(gè)渲染層同一個(gè)合成層重疊時(shí),這些渲染層會(huì)被壓縮到一個(gè) GraphicsLayer 中,以防止由于重疊原因?qū)е驴赡艹霈F(xiàn)的“層爆炸”。這句話不好理解,具體可以看看這個(gè)例子:

  • 還是之前的模型,只不過(guò)這次不同的是,有四個(gè) absolute 定位的 div 在屏幕內(nèi)發(fā)生了交疊。此時(shí)處于最下方的 div 在加上了 CSS 屬性 transform: translateZ(0) 后被瀏覽器提升為合成層,如果按照隱式合成的原理,蓋在它上邊的 div 會(huì)提升為一個(gè)新的合成層,第三個(gè) div 又蓋在了第二個(gè)上,自然也會(huì)被提升為合成層,第四個(gè)也同理。這樣一來(lái),豈不是就會(huì)產(chǎn)生四個(gè)合成層了?

  • 然而事實(shí)并不是這樣的,瀏覽器的層壓縮機(jī)制,會(huì)將隱式合成的多個(gè)渲染層壓縮到同一個(gè) GraphicsLayer 中進(jìn)行渲染,也就是說(shuō),上方的三個(gè) div 最終會(huì)處于同一個(gè)合成層中,這就是瀏覽器的層壓縮。

當(dāng)然了,瀏覽器的自動(dòng)層壓縮并不是萬(wàn)能的,有很多特定情況下,瀏覽器是無(wú)法進(jìn)行層壓縮的,無(wú)線性能優(yōu)化:Composite[5] 這篇文章列舉了許多詳細(xì)的場(chǎng)景。

基于層合成的頁(yè)面渲染優(yōu)化

一、層合成的得與失

層合成是一個(gè)相對(duì)復(fù)雜的瀏覽器特性,為什么我們需要關(guān)注這么底層又難理解的東西呢?那是因?yàn)殇秩緦犹嵘秊楹铣蓪又?,?huì)給我們帶來(lái)不少好處:

  • 合成層的位圖,會(huì)交由 GPU 合成,比 CPU 處理要快得多;

  • 當(dāng)需要 repaint 時(shí),只需要 repaint 本身,不會(huì)影響到其他的層;

  • 元素提升為合成層后,transform 和 opacity 才不會(huì)觸發(fā) repaint,如果不是合成層,則其依然會(huì)觸發(fā) repaint。

當(dāng)然了,利弊是相對(duì)和共存的,層合成也存在一些缺點(diǎn),這很多時(shí)候也成為了我們網(wǎng)頁(yè)性能問(wèn)題的根源所在:

  • 繪制的圖層必須傳輸?shù)?GPU,這些層的數(shù)量和大小達(dá)到一定量級(jí)后,可能會(huì)導(dǎo)致傳輸非常慢,進(jìn)而導(dǎo)致一些低端和中端設(shè)備上出現(xiàn)閃爍;

  • 隱式合成容易產(chǎn)生過(guò)量的合成層,每個(gè)合成層都占用額外的內(nèi)存,而內(nèi)存是移動(dòng)設(shè)備上的寶貴資源,過(guò)多使用內(nèi)存可能會(huì)導(dǎo)致瀏覽器崩潰,讓性能優(yōu)化適得其反。

二、Chrome Devtools 如何查看合成層

層合成的特性給我們提供了一個(gè)利用終端硬件能力來(lái)優(yōu)化頁(yè)面性能的方式,對(duì)于一些重交互、重動(dòng)畫(huà)的頁(yè)面,合理地利用層合成可以讓頁(yè)面的渲染效率得到極大提升,改善交互體驗(yàn)。而我們需要關(guān)注的是如何規(guī)避層合成對(duì)頁(yè)面造成的負(fù)面影響,或者換個(gè)說(shuō)法來(lái)講,更多時(shí)候是如何權(quán)衡利害,合理組織頁(yè)面的合成層,這就要求我們事先要對(duì)頁(yè)面的層合成情況有一個(gè)詳細(xì)的了解。Chrome Devtools 給我們提供了一些工具,可以方便的查看頁(yè)面的合成層情況。

首先是看看頁(yè)面的渲染情況,以一個(gè)欄目頁(yè)為例,點(diǎn)擊 More tools -> Rendering,選擇 Layer borders,你就能看到頁(yè)面中的合成層都帶上了黃色邊框。

這還不夠,我們還需要更加詳盡的層合成情況,點(diǎn)擊 More tools -> Layers,你可以看到像這樣的一個(gè)視圖:

左側(cè)列出了所有提升為獨(dú)立合成層的元素,右側(cè)則是一個(gè)整體合成層邊界視圖,以及選定合成層的詳細(xì)情況,包括以下幾個(gè)比較關(guān)鍵的信息:

  • Size:合成層的大小,其實(shí)也就是對(duì)應(yīng)元素的尺寸;

  • Compositing Reasons:形成復(fù)合層原因,這是最關(guān)鍵的,也是我們分析問(wèn)題的突破口,比如圖中的合成層產(chǎn)生的原因就是交疊問(wèn)題;

  • Memory estimate:內(nèi)存占用估算;

  • Paint count:繪制次數(shù);

  • Slow scroll regions:緩慢滾動(dòng)區(qū)域。

可以看出我們?cè)诓唤?jīng)意間就已經(jīng)制造出了很多意料之外的合成層,這些沒(méi)有實(shí)際意義的合成層都是可以被優(yōu)化的。

三、一些優(yōu)化建議

1、動(dòng)畫(huà)使用 transform 實(shí)現(xiàn)

對(duì)于一些體驗(yàn)要求較高的關(guān)鍵動(dòng)畫(huà),比如一些交互復(fù)雜的玩法頁(yè)面,存在持續(xù)變化位置的 animation 元素,我們最好是使用 transform 來(lái)實(shí)現(xiàn)而不是通過(guò)改變 left/top 的方式。這樣做的原因是,如果使用 left/top 來(lái)實(shí)現(xiàn)位置變化,animation 節(jié)點(diǎn)和 Document 將被放到了同一個(gè) GraphicsLayer 中進(jìn)行渲染,持續(xù)的動(dòng)畫(huà)效果將導(dǎo)致整個(gè) Document 不斷地執(zhí)行重繪,而使用 transform 的話,能夠讓 animation 節(jié)點(diǎn)被放置到一個(gè)獨(dú)立合成層中進(jìn)行渲染繪制,動(dòng)畫(huà)發(fā)生時(shí)不會(huì)影響到其它層。并且另一方面,動(dòng)畫(huà)會(huì)完全運(yùn)行在 GPU 上,相比起 CPU 處理圖層后再發(fā)送給顯卡進(jìn)行顯示繪制來(lái)說(shuō),這樣的動(dòng)畫(huà)往往更加流暢。

2、減少隱式合成

雖然隱式合成從根本上來(lái)說(shuō)是為了保證正確的圖層重疊順序,但具體到實(shí)際開(kāi)發(fā)中,隱式合成很容易就導(dǎo)致一些無(wú)意義的合成層生成,歸根結(jié)底其實(shí)就要求我們?cè)陂_(kāi)發(fā)時(shí)約束自己的布局習(xí)慣,避免踩坑。

比如上邊提到的欄目頁(yè)面,就因?yàn)槠綍r(shí)開(kāi)發(fā)的不注意造成頁(yè)面生成了過(guò)多的合成層,我在試圖查看頁(yè)面合成層情況的時(shí)候,在 PC 上已經(jīng)能明顯感到卡頓了。利用 Chrome Devtools 分析之后不難發(fā)現(xiàn),頁(yè)面里邊存在的一個(gè)帶動(dòng)畫(huà) transform 的 button 按鈕,提升為了合成層,動(dòng)畫(huà)交疊的不確定性使得頁(yè)面內(nèi)其他 z-index 大于它但其實(shí)并沒(méi)有交疊的節(jié)點(diǎn)也都全部提升為了合成層(這個(gè)原因真的好坑)。

這個(gè)時(shí)候我們只需要把這個(gè)動(dòng)畫(huà)節(jié)點(diǎn)的 z-index 屬性值設(shè)置得大一些,讓層疊順序高過(guò)于頁(yè)面其他無(wú)關(guān)節(jié)點(diǎn)就行。當(dāng)然并不是盲目地設(shè)置 z-index 就能避免,有時(shí)候 z-index 也還是會(huì)導(dǎo)致隱式合成,這個(gè)時(shí)候可以試著調(diào)整一下文檔中節(jié)點(diǎn)的先后順序直接讓后邊的節(jié)點(diǎn)來(lái)覆蓋前邊的節(jié)點(diǎn),而不用 z-index 來(lái)調(diào)整重疊關(guān)系。方法不是唯一的,具體方式還是得根據(jù)不同的頁(yè)面具體分析。

改善后的頁(yè)面效果如下,可以看到相比優(yōu)化前,我們消除了很多無(wú)意義的合成層。

3、減小合成層的尺寸

舉個(gè)簡(jiǎn)單的例子,分別畫(huà)兩個(gè)尺寸一樣的 div,但實(shí)現(xiàn)方式有點(diǎn)差別:一個(gè)直接設(shè)置尺寸 100x100,另一個(gè)設(shè)置尺寸 10x10,然后通過(guò) scale 放大 10 倍,并且我們讓這兩個(gè) div 都提升為合成層:

<style> .bottom, .top { position: absolute; will-change: transform; } .bottom { width: 100px; height: 100px; top: 20px; left: 20px; z-index: 3; background: rosybrown; } .top { width: 10px; height: 10px; transform: scale(10); top: 200px; left: 200px; z-index: 5; background: indianred; }</style><body> <div class='bottom'></div> <div class='top'></div></body>

利用 Chrome Devtools 查看這兩個(gè)合成層的內(nèi)存占用后發(fā)現(xiàn),.bottom 內(nèi)存占用是 39.1 KB,而 .top 是 400 B,差距十分明顯。這是因?yàn)?.top 是合成層,transform 位于的 Composite 階段,現(xiàn)在完全在 GPU 上執(zhí)行。因此對(duì)于一些純色圖層來(lái)說(shuō),我們可以使用 width 和 height 屬性減小合成層的物理尺寸,然后再用 transform: scale(…) 放大,這樣一來(lái)可以極大地減少層合成帶來(lái)的內(nèi)存消耗。


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多