我們經常說到瀏覽器的性能問題,其實與瀏覽器性能息息相關的一點就是瀏覽器如何渲染我們的網頁,這個時候我們就會涉及到一個概念,那就是瀏覽器的回流(重排,以下統稱回流,Reflow)與重繪(Repaint)。
回流
對回流這個詞,我的理解是回爐重造,即對于整個網頁重新渲染一遍。那我們可以思考一下,從性能角度來講,如果我們來寫瀏覽器的代碼,一定是再必須要重新渲染網頁的時候再重新渲染,那就推出一個問題,什么時候瀏覽器必須要重新渲染網頁?
其實必定是當網頁的元素坐標發生變化的時候,這里我們可以理解為有很多人在排隊,大家僅僅的依靠在一起,那什么時候大家需要都挪動下位置呢?我覺得要么就是一個人或者幾個人突然變胖了/瘦了,那大家如果想要繼續依靠在一起,就得都動一動;或者其中一個人或者幾個人挪動了一下自己的位置,他勢必也會擠著其他人去動一動位置。這種重新渲染全部或部分文檔的動作我們就叫做回流,因為大家都需要挪動下位置,也就導致我們這個網頁需要回爐重造了。
所以會導致回流的操作(包括但不限于):
頁面首次渲染
瀏覽器窗口大小發生改變
元素尺寸或位置發生改變
元素內容變化(文字數量或圖片大小等等)
元素字體大小變化
添加或者刪除可見的
DOM
元素激活
CSS
偽類(例如::hover
)
重繪
還是拿排隊舉例,當隊伍中的一個人需要換一件衣服,比如他從穿黃衣服換成穿紅色的衣服,這個時候只要這一個人換件衣服就行了,對其他人并沒有影響,這種情況我們就叫做重繪。瀏覽器只需要對該元素進行重新繪制即可。
所以會導致回流的操作(包括但不限于):
- 修改color/background-color/visibility
由上述可見,其實回流對瀏覽器性能的消耗是高于重繪的,而且回流的操作一定會伴隨著重繪,重繪卻不一定伴隨回流。那現代瀏覽器其實對這塊是有進行優化處理的,如果我們的隊伍總是需要變換位置,我們就統一來一次大排隊。
那么我們在平時的工作中,如果針對于回流和重繪寫出性能更好地代碼呢?有以下幾點可以注意的:
CSS
避免使用
table
布局。盡可能在
DOM
樹的最末端改變class
。避免設置多層內聯樣式。
將動畫效果應用到
position
屬性為absolute
或fixed
的元素上。避免使用
CSS
表達式(例如:calc()
)。
JavaScript
避免頻繁操作樣式,最好一次性重寫
style
屬性,或者將樣式列表定義為class
并一次性更改class
屬性。避免頻繁操作
DOM
,創建一個documentFragment
,在它上面應用所有DOM操作
,最后再把它添加到文檔中。也可以先為元素設置
display: none
,操作結束后再把它顯示出來。因為在display
屬性為none
的元素上進行的DOM
操作不會引發回流和重繪。避免頻繁讀取會引發回流/重繪的屬性,如果確實需要多次使用,就用一個變量緩存起來。
對具有復雜動畫的元素使用絕對定位,使它脫離文檔流,否則會引起父元素及后續元素頻繁回流。
參考 瀏覽器的回流與重繪 (Reflow & Repaint)
博客地址 北落師門