瀏覽器解析HTML的過程
1.構(gòu)建 frame, 以建立DOM樹。
2.回流(reflow) 引起Dom樹結(jié)構(gòu)變化,改變頁面布局。 3.重繪(repaint) 不會引起Dom樹變化及頁面布局變化,只重新渲染頁面樣式
回流與重繪兩者之間的聯(lián)系在于: 觸發(fā)回流一定會觸發(fā)重繪, 而觸發(fā)重繪卻不一定會觸發(fā)回流。
我們可以把頁面理解為一個(gè)黑板,黑板上有一朵畫好的小花?,F(xiàn)在我們要把這朵從左邊(left)移到了右邊(right),那我們是不是要先確定好右邊的具體位置,畫好形狀(回流),再畫上它原有的顏色(重繪)。
但如果我們僅僅是想換給花朵換一個(gè)顏色,那么只需擦掉花朵上的顏色,再重新涂上自己期望的顏色(重繪)就可以了。
1. 回流(Reflow)
當(dāng)Render Tree中部分或全部元素的尺寸,結(jié)構(gòu)或者某些屬性發(fā)生改變時(shí),瀏覽器重新渲染部分或全部文檔的過程
導(dǎo)致回流發(fā)生的一些因素:
瀏覽器窗口大小發(fā)生改變
元素字體大小變化
增加或者移除樣式表
內(nèi)容變化,比如用戶在 input 框中輸入文字, CSS3 動畫,文字?jǐn)?shù)量或者圖片大小改變等
激活
CSS偽類,比如:hover操作
class屬性添加或刪除可見的DOM元素
計(jì)算
offsetWidth和offsetHeight屬性設(shè)置
style屬性的值頁面首次渲染
元素尺寸或者位置發(fā)生改變
一些常用且會導(dǎo)致回流的屬性和方法:
clientWidth,clientHeight,clientTop,clientLeft
offsetWidth,offsetHeight,offsetTop,offsetLeftscrollWidth,scrollHeight,scrollTop,scrollLeft,scrollIntoView()
2. 重繪(Repaint)
而重繪則是視覺效果變化引起的重新繪制。比如 color 或者 background 發(fā)生了變化,那就該給觸發(fā)重繪的元素化化妝,化成它想要的樣子。
3.性能影響
回流比重繪的代價(jià)要更高
有時(shí)僅僅回流一個(gè)單一的元素,它的父元素以及任何跟隨它的元素也會產(chǎn)生回流
現(xiàn)代瀏覽器會對頻繁的回流或重繪操作進(jìn)行優(yōu)化:
瀏覽器會維護(hù)一個(gè)隊(duì)列,把所有引起回流和重繪的操作放入到隊(duì)列中,如果隊(duì)列中的任務(wù)數(shù)量或者時(shí)間間隔達(dá)到一個(gè)閾值,瀏覽器會將隊(duì)列清空,進(jìn)行一次批處理,這樣可以把多次回流和重繪變成一次
4.如何避免回流和重繪
CSS:
1、避免使用table布局。 2、盡可能在DOM樹的最末端改變class。 3、避免設(shè)置多層內(nèi)聯(lián)樣式。 4、將動畫效果應(yīng)用到position屬性為absolute或fixed的元素上。 5、避免使用CSS表達(dá)式(例如:calc())。
JavaScript:
1、避免頻繁操作樣式,最好一次性重寫style屬性,或者將樣式列表定義為class并一次性更改class屬性。 2、避免頻繁操作DOM,創(chuàng)建一個(gè)documentFragment,在它上面應(yīng)用所有DOM操作,最后再把它添加到文檔中。 3、也可以先為元素設(shè)置display: none,操作結(jié)束后再把它顯示出來。因?yàn)樵赿isplay屬性為none的元素上進(jìn)行的DOM操作不會引發(fā)回流和重繪。 4、避免頻繁讀取會引發(fā)回流/重繪的屬性,如果確實(shí)需要多次使用,就用一個(gè)變量緩存起來。 5、對具有復(fù)雜動畫的元素使用絕對定位,使它脫離文檔流,否則會引起父元素及后續(xù)元素頻繁回流。