瀏覽器的大概工作流程
以普通的HTML頁面為例:
- 解析HTML文件,生成dom樹
- 解析css產生css規則樹
- 解析JavaScript,通過DOM-API來操作dom樹和css規則樹
- 通過dom樹和css規則樹來構造渲染樹(rendering tree)
- 呼叫作業系統的GUI介面畫頁面
迴流(reflow)和重繪(repaint)
迴流:
元素的大小尺寸、位置發生變化時,會重新計算渲染樹,頁面要進行重新排版工作,這個過程即是迴流。<br>
重繪:
元素做了一些不影響排版的改變,比如背景色、下劃線等等,只需要重新繪製的過程,叫做重繪。
顯然迴流帶來的代價大於重繪,因為重繪僅僅是重新畫一遍元素而已,但是重繪是重新計算+重新畫。
迴流的原因:
- Initial。網頁初始化的時候。
- Incremental。一些Javascript在操作DOM Tree時。
- Resize。其些元件的尺寸變了
- StyleChange。如果CSS的屬性發生變化了。
- Dirty。幾個Incremental的reflow發生在同一個元素的子樹上。
更具體的說,就是這些常見的操作會引起迴流:
- 調整視窗大小
- 字型大小
- 樣式表變動
- 元素內容變化,尤其是輸入控制元件
- CSS偽類啟用,在使用者互動過程中發生
- DOM操作,DOM元素增刪、修改
- width, clientWidth, scrollTop等佈局寬高的計算
ps:但是瀏覽器並不會在我們一進行上面的操作就進行迴流,瀏覽器會積攢一批reflow然後一起進行迴流,不過有的操作會讓瀏覽器立馬進行迴流,比如resize視窗,改變了頁面預設的字型,或者說獲取以下這些值:
- offsetTop, offsetLeft, offsetWidth, offsetHeight
- scrollTop/Left/Width/Height
- clientTop/Left/Width/Height
- IE中的 getComputedStyle(), 或 currentStyle
如何減少reflow和repaint
- 避免頻繁的修改樣式,可以將要修改的多個樣式定義為一個class類,然後將類名一次賦值即可
-
把dom離線操作:
- 使用documentFragment 物件在記憶體裡操作DOM
- 先把DOM給display:none(有一次reflow),然後你想怎麼改就怎麼改。比如修改100次,然後再把他顯示出來。
- clone一個DOM結點到記憶體裡,然後想怎麼改就怎麼改,改完後,和線上的那個的交換一下
- 不要把DOM結點的屬性值放在一個迴圈裡當成迴圈裡的變數。不然這會導致大量地讀寫這個結點的屬性。
- 為動畫的HTML元件使用fixed或absoult的position,那麼修改他們的CSS是不會reflow的,因為脫離了文件流