瀏覽器渲染一個頁面有兩條線程:一條是渲染js腳本,一條是渲染css腳本。但是兩條線程是互斥的。
回流:當render tree的一部分或者全部元素因改變了自身的寬高,布局,顯示或隱藏,或元素內部的文字結構發生變化,導致需要重新構建頁面的時候,回流就產生了。
重繪:當一個元素自身的寬高,布局,及顯示或隱藏沒有改變,而只是改變了元素的外觀風格的時候,就產生了重繪。
結論:回流必定觸發重繪,而重繪不一定出發回流。
如何避免回流:1、不使用能夠觸發回流的屬性;2、建立一個圖層,讓回流在圖層里面進行,限制回流和重繪的范圍,減少瀏覽器的運算工作量。
Css是怎么“划分圖層”的:在頁面加載完dom之后,瀏覽器會根據自身制定的一些特殊css 屬性對頁面進行划分為一個個圖層。例如position: absolute|fixed 。
圖層的優點:當一個元素在自己的圖層內發生變化時,他的回流和重繪只會在圖層內發生變化,減少了瀏覽器的計算量。
圖層內部做了什么:
1、對圖層里面的節點做回流和重布局運算,計算出他們的樣式
2、生成圖形和位置
3、將每個節點繪制填充在圖層位圖中
4、將塗層作為紋理發送到GPU上
5、將所有的圖層合並,顯示在瀏覽器的頁面上
總結:濫用圖層會讓頁面進行了太多的合並運算而導致頁面卡頓。所以圖層的用途應該讓那些經常要進行位置結構,布局變換的元素去使用。例如輪播圖。
有哪些可替換的屬性可以優化回流與重繪呢,一共有一下9點:
1:用transform 代替 top,left ,margin-top, margin-left... 這些位移屬性
2:用opacity 代替 visibility,但是要同時有translate3d 或 translateZ 這些可以創建的圖層的屬性存在才可以阻止回流
但是第二點經過我的實驗,發現如果不加 transform: translateZ(0) 配合opacity的話還是會產生回流的,而只用visibility 就只會產生重繪不會回流
而 opacity 加上 transform: translateZ/3d 這個屬性之后便不會發生回流和重繪了
3:不要使用 js 代碼對dom 元素設置多條樣式,選擇用一個 className 代替之。
4:如果確實需要用 js 對 dom 設置多條樣式那么可以將這個dom 先隱藏,然后再對其設置
5:不要在循環內獲取dom 的樣式例如:offsetWidth, offsetHeight, clientWidth, clientHeight... 這些。瀏覽器有一個回流的緩沖機制,即多個回流會保存在一個棧里面,當這個棧滿了瀏覽器便會一次性觸發所有樣式的更改且刷新這個棧。但是如果你多次獲取這些元素的實際樣式,瀏覽器為了給你一個准確的答案便會不停刷新這個緩沖棧,導致頁面回流增加。
所以為了避免這個問題,應該用一個變量保存在循環體外。
6:不要使用table 布局,因為table 的每一個行甚至每一個單元格的樣式更新都會導致整個table 重新布局
7:動畫的速度按照業務按需決定
8:對於頻繁變化的元素應該為其加一個 transform 屬性,對於視頻使用video 標簽
9:必要時可以開啟 GPU 加速,但是不能濫用
使用 GPU 加速提升動畫性能時,最好給當前動畫元素增加一個高一點的 z-index 屬性,人為干擾復合層的排序,可以有效減少 Chrome 創建不必要的復合層,提升渲染性能。
什么是 16ms 優化?
- 大多數設備的刷新頻率是 60 次/秒,(1000/60 = 16.6ms)也就說是瀏覽器對每一幀畫面的渲染工作要在 16ms 內完成,超出這個時間,頁面的渲染就會出現卡頓現象,影響用戶體驗。
- 瀏覽器在一幀里面,會依次執行以下這些動作。減少或者避免 layout,paint 可以讓頁面不卡頓,動畫效果更加流暢。
- JavaScript:JavaScript 實現動畫效果,DOM 元素操作等。
- Style(計算樣式):確定每個 DOM 元素應該應用什么 CSS 規則。
- Layout(布局):計算每個 DOM 元素在最終屏幕上顯示的大小和位置。由於 web 頁面的元素布局是相對的,所以其中任意一個元素的位置發生變化,都會聯動的引起其他元素發生變化,這個過程叫 reflow。
- Paint(繪制):在多個層上繪制 DOM 元素的的文字、顏色、圖像、邊框和陰影等。
- Composite(渲染層合並):按照合理的順序合並圖層然后顯示到屏幕上。