前言:
在了解回流與重繪之前,我們先來了解下瀏覽器的渲染機制:
1. 瀏覽器采用的是流式布局模型(Flow Based Layout)
2. 瀏覽器會把CSS解析成CSSOM Tree,把HTML解析成 DOM Tree,把這兩個合並成 Render Tree
3. 有了Render Tree 我們就知道了所有節點的位置和樣式,瀏覽器就開始計算他們在頁面中的位置,然后開始繪制
4. 由於瀏覽器是流式布局,對於Render Tree的計算通常只需要遍歷一遍就可以完成。但是table及其內部的元素除外,他們可能要計算多次,需要花費等同的元素3倍的時間,這也是不推薦使用table的原因。
回流(Reflow)
當Render Tree 中的部分或全部元素的尺寸,結構或者處罰某些屬性時,瀏覽器會重新計算並渲染頁面,稱為回流。此時瀏覽器需要重新進行計算,計算后還需要重新頁面布局,因此是較重的操作。
會導致回流的操作有:
- 頁面初次渲染
- 瀏覽器窗口發生改變
- 元素尺寸,位置,內容發生變化
- 元素字體大小變化
- 添加或者刪除的可見dom元素
- 激活CSS偽類,例如 :hover
- 查詢某些屬性或調用某些方法
一些常用的會導致回流的屬性或方法
- clientWidth, clientHeight, clientTop, clientLeft
- offsetWidth, offsetHeight, offsetTop, offsetLeft
- scrollWidth, scrollHeight, scrollTop, scrollLeft
- scrollIntorView(), scrollInToViewIfNeeded()
- getComputedStyle()
- getBoundingClientRect()
- scrollTop
- ...
重繪(Repaint)
當元素的樣式改變不影響布局時(例如:color, background-color, visibility等),瀏覽器將使用重繪對元素進行更新,此時由於只需要對UI層面重新繪制,因此損耗較少
回流一定會導致重繪,但是重繪不一定會導致回流
如何避免:
CSS
- 避免使用table布局
- 盡可能在DOM樹的最末端改變class
- 避免設置多層內聯樣式
- 避免CSS表達式
JavaScript
- 避免頻繁的操作樣式,最好一次性寫好style屬性,或者將樣式定義為calss,並一次性更改class屬性
- 避免頻繁操作DOM,創建一個 documentFragment ,這這個上面應用所有的DOM操作,最后再把它添加到文檔中
- 也可以先設置為display:none; 操作結束后再把它顯示出來,因為在dispkay屬性為none的元素上進行DOM操作不會引起回流和重繪
- 避免頻繁讀取引發回流、重繪的屬性,如果要多次使用,建議先把它緩存起來
- 對具有復雜動畫的元素使用絕對定位,使它脫離文檔流,否則會引起父元素及后續元素頻繁回流。