你不知道的前端性能優(yōu)化 - 布局與樣式 (二)
前言:所有的優(yōu)化點都有其適用的條件,所有的優(yōu)化點都能夠量化看到效果,具體項目具體分析,并不是每個項目都能適用這里的每個點,望周知。
布局與樣式
在提出優(yōu)化點之前,我們先明白幾個瀏覽器渲染的重要概念,重繪(reflow) 、 回流(repaint)和圖層(layer)。
上一篇其實應該說了一些,在整個頁面被渲染出來之前會進行 layout(布局) 和 paint (繪制)的過程。
簡單的說
? 重繪:其實就是觸發(fā)瀏覽器的 paint 的過程。
? 回流:其實不僅僅是觸發(fā)了 paint 的過程還觸發(fā) layout 的過程,觸發(fā)順序由后往前。
也就是說 回流相當于 layout -> patint ; 重繪相當于 patint的過程, 所以回流必定觸發(fā)重繪,重繪不一定觸發(fā)回流。
還有一個重要的概念 Layer (圖層),我們怎么理解它呢,其實圖層就相當瀏覽器分層的渲染策略,比如我們可以舉一些原生就會增加 Layer 的標簽: <canvas> <video> (除了這些還有,下面會講到)。當遇到這些標簽的時候,瀏覽器會生成一個新的圖層,之后該元素內(nèi)的重繪和回流的過程只存在于該圖層中,之后再進行圖層的合并過程。 那么重繪和回流的效率就會提高,額外增加了一個圖層的合并(composite Layers)的過程。
有沒有一種方式可以避免重繪和回流呢?那么就是用CSS啟用硬件加速。
硬件加速就是GPU加速很多電腦顯卡都支持GPU加速。
-
能觸發(fā)回流的樣式:
width top text-align height bottom overflow-y padding left font-weight margin right overflow display position font-family border-width float line-height border clear vertival-align min-height white-space font-size -
只觸發(fā)重繪的樣式:
color background outline-color border-style background-image outline border-radius background-position outline-style visibility background-repeat outline-width text-decoration background-size box-shadow -
能觸發(fā)回流的
jsoffsetTop scrollTop clientTop width getComputedStyle() offsetLeft scrollLeft clientLeft height IE的:currentStyle offsetWidth scrollWidth clientWidth getBoundingClientRect() offsetHeight scrollHeight clientHeight 除了上面的這些還有,只要是獲取元素位置相關(guān)的,瀏覽器都會在當前時間點去計算得到該屬性,該計算的過程就會觸發(fā)回流。
-
開啟GPU加速的方式常見的觸發(fā)硬件加速的css屬性:
transform
opacity
filters
-
Will-change
will-change介紹-來自MDN
對于動畫的其它屬性,比如background-color,width等,還是會引起回流重繪的,不過可以提升這些動畫的性能
明白了以上的概念后,我們就可以引出下面的優(yōu)化點了。
-
減少回流重繪
相對來說回流是一個性能比較低的過程。布局、定位和文字的改變往往都會觸發(fā)回流。對照上表有以下的優(yōu)化點,
在布局上:
可以用translate替代top/left...改變
本質(zhì)上是啟用了GPU加速渲染用opacity替代visibility
因為如果使用opacity不一定會產(chǎn)生重繪。
在操作
dom元素上:- 不要一條一條地修改 DOM 的樣式,預先定義好 class,然后修改 DOM 的 className
- 把 DOM 離線后修改,比如:先把 DOM 給 display:none (有一次 Reflow),然后你修改100次,然后再把它顯示出來,當然每個瀏覽器都做了相應的優(yōu)化所以沒必要這么弄
- 不要把 DOM 結(jié)點的屬性值放在一個循環(huán)里當成循環(huán)里的變量,例如循環(huán)調(diào)用
getBoundingClientRect()方法,將會導致頁面一直處于回流的過程。 - 不要使用
table布局,因為你改動一點點都將影響整個table的布局 - 動畫實現(xiàn)的速度的選擇
-
對于動畫新建圖層
這是一種很好的方式,之后的重繪和回流就都只在該圖層中進行了。谷歌瀏覽器創(chuàng)建圖層的條件如下:- 3D或透視變換(perspective transform)CSS屬性
- 使用加速視頻解碼的
<video>節(jié)點 - 擁有3D(WebGL)上下文或加速的2D上下文的
<canvas>節(jié)點 - 混合插件(如Flash)
- 對自己的opacity做CSS動畫或使用一個動畫webkit變換的元素
- 擁有加速CSS過濾器的元素
- 元素有一個包含復合層的后代節(jié)點(一個元素擁有一個子元素,該子元素在自己的層里)
- 元素有一個z-index較低且包含一個復合層的兄弟元素(換句話說就是該元素在復合層上面渲染)
- 啟用 GPU 硬件加速
使用transform、opacity、filters、Will-change可以啟用GPU加速
圖層不能無限制的創(chuàng)建,超過一定范圍后反而會將頁面變得更卡。這是由于圖層雖然減少了重繪和回流的時間,但是增加了圖層合并的步驟,如果很多圖層合并將導致頁面卡死。
此外還有很多種方式能夠減少布局帶來的性能損耗。js的執(zhí)行會阻塞布局的渲染所以js方面的優(yōu)化往往更優(yōu)于布局層面上的優(yōu)化,js層面上的優(yōu)化能看到的效果比較顯著,所以在真實的項目中,這種布局上的優(yōu)化往往很少人去做。
總結(jié)一下:
- 在布局上盡量使用GPU加速,盡量使用
transform代替left \ ... - 對于頁面的動畫,我們最好新建圖層,把回流和重繪的消耗降低
- 不在
js上持續(xù)的獲取dom元素的定位屬性 -
js優(yōu)化帶來的效益高,所以布局層面上的優(yōu)化比較少人做,所以這些東西得養(yǎng)成布局習慣。
本文章由作者自學完前端性能優(yōu)化后的自述,如有不正 歡迎大佬們在評論席交流。
其它篇幅傳送門:
你不知道的前端性能優(yōu)化 一 靜態(tài)資源優(yōu)化
你不知道的前端性能優(yōu)化 二 布局于樣式
你不知道的前端性能優(yōu)化 三 緩存優(yōu)化
