文章目錄
- css圖層
- 圖層創建的條件
- 重繪(Repaint)
- 回流
- 觸發重繪的屬性
- 觸發回流的屬性
- 常見的觸發回流的操作
- 優化方案
- requestAnimationFrame----請求動畫幀
- 寫在最后
學習目標:
- 了解前端Dom代碼、css樣式、js邏輯代碼到瀏覽器展現過程
- 了解什么是圖層
- 了解重繪與回流
- 了解前端層面針對重繪、回流如何優化
css圖層
瀏覽器在渲染一個頁面時,會將頁面分為很多個圖層,圖層有大有小,每個圖層上有一個或多個節點。
也就是我們各種各樣的Dom標簽
在渲染DOM的時候,瀏覽器所做的工作實際上是:
1. 獲取DOM后分割為多個圖層
2. 對每個圖層的節點計算樣式結果 (Recalculate style–樣式重計算)
3. 為每個節點生成圖形和位置 (Layout–布局,重排,回流)
4. 將每個節點繪制填充到圖層位圖中 (Paint–重繪)
5. 圖層作為紋理上傳至GPU
6. 組合多個圖層到頁面上生成最終屏幕圖像 (Composite Layers–圖層重組)
圖層創建的條件
Chrome瀏覽器滿足以下任意情況就會創建圖層:
1. 擁有具有3D變換的CSS屬性
2. 使用加速視頻解碼的節點
3. 節點
4. CSS3動畫的節點
5. 擁有CSS加速屬性的元素(will-change)
重繪(Repaint)
重繪是一個元素外觀的改變所觸發的瀏覽器行為,例如改變outline、背景色等屬性。瀏覽器會根據元素的新屬性重新繪制,
使元素呈現新的外觀。重繪不會帶來重新布局,所以并不一定伴隨回流。
需要注意的是:重繪是以圖層為單位,如果圖層中某個元素需要重繪,那么整個圖層都需要重繪。
所以為了提高性能,我們應該讓這些“變化的東西”擁有一個自己一個圖層,
不過好在絕大多數的瀏覽器自己會為CSS3動畫的節點自動創建圖層。
回流
渲染對象在創建完成并添加到渲染樹時,并不包含位置和大小信息。計算這些值的過程稱為布局或回流
“重繪"不一定需要"回流”,比如改變某個網頁元素的顏色,就只會觸發"重繪",不會觸發"回流",因為布局沒有改變。
“回流"大多數情況下會導致"重繪”,比如改變一個網頁元素的位置,就會同時觸發"回流"和"重繪",因為布局改變了。
觸發重繪的屬性
* 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
觸發回流的屬性
* 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
常見的觸發回流的操作
Reflow(回流) 的成本比 Repaint(重繪) 的成本高很多很多。
一個結點的 Reflow 很有可能導致子結點,甚至父點以及同級結點的 Reflow。
在一些高性能的電腦上也許還沒什么,但是如果 Reflow 發生在手機上,那么這個過程是非常痛苦和耗電的。
所以,下面這些動作有很大可能會是成本比較高的。
當你增加、刪除、修改 DOM 結點時,會導致 Reflow , Repaint。
當你移動 DOM 的位置
當你修改 CSS 樣式的時候。
當你 Resize 窗口的時候(移動端沒有這個問題,因為移動端的縮放沒有影響布局視口)
當你修改網頁的默認字體時。
【獲取某些屬性時(width,height…)!!!!!】
注:display:none 會觸發 reflow,而 visibility:hidden 只會觸發 repaint,因為沒有發生位置變化。
優化方案
我們已知:瀏覽器渲染頁面時經歷了如下“細致”的環節:
1. 計算需要被加載到節點上的樣式結果(Recalculate style–樣式重計算)
2. 為每個節點生成圖形和位置(Layout–重排或回流)
3. 將每個節點填充到圖層中(Paint–重繪)
4. 組合圖層到頁面上(Composite Layers–圖層重組)
如果我們需要提升性能,需要做的就是減少瀏覽器在運行時所需要做的工作,即:盡量減少1234步。
【具體優化方案如下】:
1.元素位置移動變換時盡量使用CSS3的transform來代替對top left等的操作
變換(transform)和透明度(opacity)的改變僅僅影響圖層的組合
2.【使用opacity來代替visibility】
(1).使用visibility不觸發回流,但是依然重繪。
(2).直接使用opacity即觸發重繪,又觸發回流(GPU底層設計如此!)。
(3).opacity配合圖層使用,即不觸發重繪也不觸發回流。
原因:
透明度的改變時,GPU在繪畫時只是簡單的降低之前已經畫好的紋理的alpha值來達到效果,并不需要整體的重繪。
不過這個前提是這個被修改opacity本身必須是一個圖層。
3.【不要使用table布局】
table-cell
4.將【多次改變樣式屬性的操作合并成一次】操作
不要一條一條地修改DOM的樣式,預先定義好class,然后修改DOM的className
5.【將DOM離線后再修改】
由于display屬性為none的元素不在渲染樹中,對隱藏的元素操作不會引發其他元素的回流。
如果要對一個元素進行復雜的操作時,可以先隱藏它,操作完成后再顯示。這樣只在隱藏和顯示時觸發2次回流。
6.【利用文檔碎片】(documentFragment)------vue使用了該種方式提升性能。
7.【不要把獲取某些DOM節點的屬性值放在一個循環里當成循環的變量】
當你請求向瀏覽器請求一些 style信息的時候,就會讓瀏覽器flush隊列,比如:
1. offsetTop, offsetLeft, offsetWidth, offsetHeight
2. scrollTop/Left/Width/Height
3. clientTop/Left/Width/Height
4. width,height
當你請求上面的一些屬性的時候,瀏覽器為了給你最精確的值,需要刷新內部隊列,
因為隊列中可能會有影響到這些值的操作。即使你獲取元素的布局和樣式信息跟最近發生或改變的布局信息無關,
瀏覽器都會強行刷新渲染隊列。
8.動畫實現過程中,啟用GPU硬件加速:transform: tranlateZ(0)
9.為動畫元素新建圖層,提高動畫元素的z-index
10.編寫動畫時,盡量使用如下的API
requestAnimationFrame----請求動畫幀
1.window.requestAnimationFrame()
說明:該方法會告訴瀏覽器在下一次重繪回流之前調用你所指定的函數
1.參數:該方法使用一個回調函數作為參數,這個回調函數會在瀏覽器下一次重繪之前調用。
回調函數會被自動傳入一個參數,DOMHighResTimeStamp,標識requestAnimationFrame()開始觸發回調函數的當前時間
2.返回值:
一個 long 整數,請求 ID ,是回調列表中唯一的標識。是個非零值,沒別的意義。你可以傳這個值給 window.cancelAnimationFrame() 以取消回調函數。
備注:若你想在瀏覽器下次重繪之前繼續更新下一幀動畫,那么回調函數自身必須再次調用window.requestAnimationFrame()
2.window.cancelAnimationFrame(requestID)
取消一個先前通過調用window.requestAnimationFrame()方法添加到計劃中的動畫幀請求。
requestID是先前調用window.requestAnimationFrame()方法時返回的值,它是一個時間標識,用法與定時器的id類似。
寫在最后
?原創不易,還希望各位大佬支持一下\textcolor{blue}{原創不易,還希望各位大佬支持一下}原創不易,還希望各位大佬支持一下
👍 點贊,你的認可是我創作的動力!\textcolor{green}{點贊,你的認可是我創作的動力!}點贊,你的認可是我創作的動力!
?? 收藏,你的青睞是我努力的方向!\textcolor{green}{收藏,你的青睞是我努力的方向!}收藏,你的青睞是我努力的方向!
?? 評論,你的意見是我進步的財富!\textcolor{green}{評論,你的意見是我進步的財富!}評論,你的意見是我進步的財富!
文章看完了,參與個投票吧,前端目前比較火的三大框架你更喜歡哪個?