當Render Tree中部分或全部元素的尺寸诵冒、結(jié)構(gòu)沦童、或某些屬性發(fā)生改變時撑碴,瀏覽器重新渲染部分或全部文檔的過程稱為reflow撑教。
什么時候引起重排?
1.頁面渲染初始化
2.DOM樹的結(jié)構(gòu)改變
包括了:
- 添加或者刪除DOM結(jié)點
- 元素內(nèi)容變化(文字的數(shù)量醉拓、文字的大小伟姐、圖片的大小收苏、圖片的更換)
3.render樹變化
- 元素尺寸或位置發(fā)生改變(如padding的修改)
- display屬性改為可見。
- 激活CSS偽類(例如::hover)
4. 瀏覽器窗口大小發(fā)生改變(resize事件觸發(fā))
5. 最復(fù)雜的一種:獲取某些屬性愤兵,引發(fā)回流很多瀏覽器會對回流做優(yōu)化鹿霸,他會等到足夠數(shù)量的變化發(fā)生,在做一次批處理回流秆乳。offsetHeight屬性需要返回最新的布局信息懦鼠,因此瀏覽器不得不執(zhí)行渲染隊列中的“待處理變化”并觸發(fā)重排以返回正確的值。
- offsetTop, offsetLeft, offsetWidth, offsetHeight
- scrollTop/Left/Width/Height
- clientTop/Left/Width/Height
- width,height
- 調(diào)用了getComputedStyle(), 或者 IE的 currentStyle
回流一定伴隨著重繪矫夷,而重繪卻可以單獨出現(xiàn)
減少回流葛闷?
- 避免逐項更改樣式憋槐。最好一次性更改style屬性双藕,或者將樣式列表定義為class并一次性更改class屬性。
// 不推薦的寫法:
var ele = document.getElementById('myDiv');
ele.style.borderLeft = '1px';
ele.style.borderRight = '2px';
ele.style.padding = '5px';
// 推薦的寫法:
var ele = document.getElementById('myDiv');
// 1. 重寫style
ele.style.cssText = 'border-left: 1px; border-right: 2px; padding: 5px;';
// 2. add style
ele.style.cssText += 'border-left: 1px;'
// 3. use class
ele.className = 'active';
- 避免循環(huán)操作DOM阳仔。創(chuàng)建一個documentFragment或div忧陪,在它上面應(yīng)用所有DOM操作,最后再把它添加到window.document近范。
//創(chuàng)建輕量級文檔片段
var fragment = document.createDocumentFragment();
//將要加的子節(jié)點寫在fragment上
var li = document.createElement('li');
li.innerHTML = 'apple';
fragment.appendChild(li);
var li = document.createElement('li');
li.innerHTML = 'watermelon';
fragment.appendChild(li);
//當附加一個fragment到父節(jié)點時嘶摊,實際上被添加的是該fragment的子節(jié)點,而不是片斷本身
document.getElementById('fruit').appendChild(fragment);
- 避免多次讀取offsetLeft等屬性评矩。無法避免則將它們緩存到變量叶堆。
- 將復(fù)雜的元素(如動畫)絕對定位或固定定位,使它脫離文檔流斥杜。否則回流代價十分高
display:none和visibility:hidden會產(chǎn)生回流與重繪嗎虱颗?
display:none指的是元素完全不陳列出來,不占據(jù)空間蔗喂,涉及到了DOM結(jié)構(gòu)忘渔,故產(chǎn)生reflow與repaint
visibility:hidden指的是元素不可見但存在,保留空間缰儿,不影響結(jié)構(gòu)畦粮,故只產(chǎn)生repaint
參考:
深入理解瀏覽器的重繪與重排