前端頁面迴流與重繪(轉載)
1 人贊了文章
轉載自
迴流(reflow)與重繪(repaint) - 仙女不需要id - 博客園
一、概念
頁面的顯示過程分為以下幾個階段:
1、生成DOM樹(包括display:none的節點)
2、在DOM樹的基礎上根據節點的集合屬性(margin,padding,width,height等)生成render樹(不包括display:none,head節點,但是包括visibility:hidden的節點)
3、在render樹的基礎上繼續渲染顏色背景色等樣式
reflow:當render樹的一部分或者全部因為大小邊距等問題發生改變而需要重建的過程,叫做迴流
repaint:當諸如顏色背景等不會引起頁面布局變化,而只需要重新渲染的過程叫做重繪
通過上述定義,可以很明顯看出,重繪的代價要比迴流小,畢竟重繪只涉及樣式的改變,不涉及到布局。重繪就好像給人染了一個頭髮,而迴流相當於給人做了一次抽脂手術
二、什麼會引起迴流
這也是網易題目的出法
- 頁面渲染初始化
- DOM結構變化,比如刪除了某個節點;骨頭都被打斷了,肯定比抽脂更嚴重,所以會引發迴流
- render樹變化,比如減少了padding;也就是進行抽脂手術
- 窗口resize事件觸發
- 最複雜的一種:獲取某些屬性,引發迴流 很多瀏覽器會對迴流做優化,他會等到足夠數量的變化發生,在做一次批處理迴流。 但是除了render樹的直接變化。 當獲取一些屬性時,瀏覽器為了獲得正確的值也會觸發迴流。這樣就使得瀏覽器的優化失效了這些屬性包括
- offsetTop, offsetLeft, offsetWidth, offsetHeight
- scrollTop/Left/Width/Height
- clientTop/Left/Width/Height
- width,height
- 調用了getComputedStyle(), 或者 IE的 currentStyle
var
s = document.body.style;
s.padding =
"2px";
// 迴流+重繪
s.border =
"1px solid red";
// 再一次 迴流+重繪
s.color =
"blue";
// 再一次重繪
s.backgroundColor =
"#ccc";
// 再一次 重繪
s.fontSize =
"14px";
// 再一次 迴流+重繪
// 添加node,再一次 迴流+重繪
document.body.appendChild(document.createTextNode(abc!));
可以看出,迴流一定伴隨著重繪,而重繪卻可以單獨出現
可以理解為,路人甲摔斷了腿或者抽脂之後,病怏怏導致頭髮也變白了(迴流+重繪);但是炮灰乙卻僅僅是去村口王師傅那裡燙了頭(重繪)
迴流對性能產生了一定的影響,儘管瀏覽器機智地幫我們進行了批處理,但是仍然存在著上述諸多闊怕的屬性,一獲取就迴流。怎麼解決?
三、減少迴流
- 避免逐項更改樣式。最好一次性更改style屬性,或者將樣式列表定義為class並一次性更改class屬性。
- 避免循環操作DOM。創建一個documentFragment或div,在它上面應用所有DOM操作,最後再把它添加到window.document。
- 避免多次讀取offsetLeft等屬性。無法避免則將它們緩存到變數。
- 將複雜的元素絕對定位或固定定位,使它脫離文檔流。否則迴流代價十分高
補充:改變字體大小會引發迴流
回到網易的問題,並適當做延伸:display:none和visibility:hidden會產生迴流與重繪嗎?
display:none指的是元素完全不陳列出來,不佔據空間,涉及到了DOM結構,故產生reflow與repaintvisibility:hidden指的是元素不可見但存在,保留空間,不影響結構,故只產生repaint推薦閱讀:
※通過QQ音樂介面獲取數據
※React ?? 新的 Context API
※響應式布局
※大型Vuex應用程序的目錄結構
※了不起的 Gatsby.js