你將瞭解到:css
什麼是迴流
什麼是重繪
迴流什麼時候發生
重繪什麼時候發生
如何避免迴流和重繪
複製代碼
帶着上面的問題,咱們一探究竟前端
迴流:英文是reflow瀏覽器
當render tree中的一部分(或所有),由於元素的規模尺寸、佈局、隱藏等改變
而須要從新構建,這就是迴流(reflow)
複製代碼
重繪:英文是repaints緩存
當render tree中的一些元素須要更新屬性,而這些屬性只是影響元素的外
觀、風格,而不影響佈局(例如:background-color),則稱爲重繪(repaints)
複製代碼
特色:迴流必將引發重繪,重繪不必定引發迴流 迴流比重繪的代價更高bash
下述狀況會發生瀏覽器迴流:app
(1)添加或者刪除可見的DOM元素;
(2)元素位置改變;
(3)元素尺寸改變——邊距、填充、邊框、寬度和高度
(4)內容改變——好比文本改變或者圖片大小改變而引發的計算值寬度和高度改變;
(5)頁面渲染初始化;
(6)瀏覽器窗口尺寸改變——resize事件發生時;
複製代碼
let box = document.getElementById("box").style;
box.padding = "2px"; // 迴流+重繪
box.border = "1px solid red"; // 再一次 迴流+重繪
box.fontSize = "14px"; // 迴流+重繪
document.getElementById("box").appendChild(document.createTextNode('abc!'));
複製代碼
let box = document.getElementById("box").style;
box.color = "red"; // 重繪
box.backgroud-color = "blue"; // 重繪
document.getElementById("box").appendChild(document.createTextNode('abc!'));
複製代碼
因迴流的開銷較大,若是每一個操做都去迴流重繪的話,瀏覽器可能就會受不了。因此不少瀏覽器都會優化這些操做。
佈局
屢次的迴流、重繪變成一次迴流重繪:優化
瀏覽器會維護1個隊列,把全部會引發迴流、重繪的操做放入這個隊列,等
隊列中的操做到了必定的數量或者到了必定的時間間隔,瀏覽器就會flush
隊列,進行一個批處理。
複製代碼
可是有時上面的方法會失效,緣由是:動畫
有些狀況,當請求向瀏覽器請求一些style信息的時候,就會讓瀏覽器強制flush隊列,好比:
(1)offsetTop, offsetLeft, offsetWidth, offsetHeight
(2) scrollTop/Left/Width/Height
(3)clientTop/Left/Width/Height
(4)width,height
(5)請求了getComputedStyle(), 或者 IE的 currentStyle
複製代碼
當你請求上面的一些屬性的時候,瀏覽器爲了給你最精確的值,須要flush隊列,由於隊列中可能會有影響到這些值的操做。即便你獲取元素的佈局和樣式信息跟最近發生或改變的佈局信息無關,瀏覽器都會強行刷新渲染隊列。ui
這樣以來,瀏覽器的優化就顯得力不從心,因此咱們須要一些方法,儘量的避免或減小瀏覽器的迴流、重繪
(1)添加css樣式,而不是利用js控制樣式
(2)讓要操做的元素進行「離線處理」,處理完後一塊兒更新
當用DocumentFragment進行緩存操做,引起一次迴流和重繪
使用display:none技術,只引起兩次迴流和重繪
使用cloneNode(true or false)和replaceChild技術,引起一次迴流和重繪
(3)直接改變className,若是動態改變樣式,則使用cssText(考慮沒有優化的瀏覽器)
// bad
elem.style.left = x + "px";
elem.style.top = y + "px";
// good
elem.style.cssText += ";left: " + x + "px;top: " + y + "px;";
(4)不要常常訪問會引發瀏覽器flush隊列的屬性,若是你確實要訪問,利用緩存
// bad
for (var i = 0; i < len; i++) {
el.style.left = el.offsetLeft + x + "px";
el.style.top = el.offsetTop + y + "px";
}
// good
var x = el.offsetLeft,
y = el.offsetTop;
for (var i = 0; i < len; i++) {
x += 10;
y += 10;
el.style = x + "px";
el.style = y + "px";
}
(5)讓元素脫離動畫流,減小回流的Render Tree的規模
$("#block1").animate({left:50});
$("#block2").animate({marginLeft:50});
(6)將須要屢次重排的元素,position屬性設爲absolute或fixed,這樣此元素就脫離了文檔流,它的變化不會影響到其餘元素。例若有動畫效果的元素就最好設置爲絕對定位;
(7)避免使用table佈局:儘可能不要使用表格佈局,若是沒有定寬表格一列的寬度由最寬的一列決定,那麼極可能在最後一行的寬度超出以前的列寬,引發總體迴流形成table可能須要屢次計算才能肯定好其在渲染樹中節點的屬性,一般要花3倍於同等元素的時間。
(8)儘可能將須要改變DOM的操做一次完成
let box = document.getElementById("box").style;
// bad
box.color = "red"; // 重繪
box.size = "14px"; // 迴流、重繪
// good
box.bord = '1px solid red'
(9)儘量在DOM樹的最末端改變class,儘量在DOM樹的裏面改變class(能夠限制迴流的範圍)
(10)IE中避免使用JavaScript表達式
複製代碼
參考資料: