頁面的重繪與迴流,以及如何優化

瀏覽器對頁面的呈現流程css

頁面呈現流程
瀏覽器把取到的HTML代碼解析成1個DOM樹
HTML中的每一個tag都是DOM中的1個節點
根節點是document對象
DOM樹裏包含了全部HTML標籤
包括display:none;隱藏(由於DOM tree沒法識別樣式),還有用JS動態添加的元素等
瀏覽器把全部樣式解析成樣式結構體,解析過程當中會去掉瀏覽器不能識別的樣式(例如:IE會去掉-moz開頭的樣式)
DOM tree和樣式結構體組合構建render tree
render tree相似於DOM tree
render tree能識別樣式,render tree中的每一個節點都有本身的style
render tree不包含隱藏的節點(例如:display:none;的節點和head節點)
頁面加載時,不會呈現且不會影響呈現的節點不會包含到render tree中
visibility:hidden;會影響佈局(layout),會佔有空間
瀏覽器根據構建好的render tree來繪製頁面
迴流與重繪
一、概述
當render tree中的一部分(或所有),由於元素的規模尺寸、佈局、隱藏等改變而須要從新構建,這就是迴流(reflow)
每一個頁面至少迴流一次,即頁面首次加載
迴流時,瀏覽器會使渲染樹中受到影響的部分失效,並從新構造這部分渲染樹
迴流完成後,瀏覽器會從新繪製受影響的部分,是重繪過程
當render tree中的一些元素須要更新屬性,而這些屬性只是影響元素的外觀、風格,而不影響佈局(例如:background-color),則稱爲重繪(repaints)
迴流必將引發重繪,重繪不必定引發迴流
迴流比重繪的代價更高
二、迴流什麼時候發生
當頁面佈局和幾何屬性改變時就須要迴流瀏覽器

添加或者刪除可見的DOM元素
元素改變位置和計算offsetWidth和offsetHeight屬性
元素尺寸改變--邊距、填充、邊框和寬高
內容改變(例如:文本改變、圖片大小改變而引發的計算值寬度和高度改變,input框中輸入文字)
頁面渲染初始化
瀏覽器窗口尺寸改變--resize事件發生時
增長或移出樣式表
操做class屬性
改變字體
激活僞類(例如:hover)
迴流的花銷跟render tree有多少節點須要重繪有關係(好比在body最前面插入1個元素,會致使整個render tree迴流,若是在body後面插入1個元素,則不會影響前面元素的迴流)緩存

let box = document.getElementById("box").style;
box.padding = "2px"; // 迴流+重繪
box.border = "1px solid red"; // 再一次 迴流+重繪
box.color = "blue"; // 重繪
box.backgroundColor = "#ccc"; // 重繪
box.fontSize = "14px"; // 迴流+重繪
document.getElementById("box").appendChild(document.createTextNode('abc!'));
三、瀏覽器優化
上面的代碼在Chrome瀏覽器中其實是看不出差異的,由於不少瀏覽器都會優化這些操做。瀏覽器會維護1個隊列,把全部引發迴流、重繪的操做放入這個隊列,等隊列中的操做到了必定的數量或者到了必定時間間隔,瀏覽器就會flush隊列,進行一個批處理。這樣讓屢次迴流和重繪變成一次迴流重繪。
某些狀況下瀏覽器優化會不起做用,當瀏覽器請求一些style信息的時候,會讓瀏覽器flush隊列,好比:app

offsetTop/offsetLeft/offsetWidth/offsetHeight
scrollTop/Left/Width/Height
clientTop/Left/Width/Height
width,height
請求了getComputedStyle(), 或者 IE的 currentStyle
請求上面一些屬性的時候,瀏覽器爲了給出精確值,須要flush隊列,由於隊列中可能會影響到這些值得操做,因此瀏覽器會強行刷新渲染隊列。佈局

如何減小回流、重繪
減小回流、重繪就是須要減小對render tree的操做,並減小對一些style信息的請求,合理利用瀏覽器優化策略。有一下方法:字體

直接改變className,若是動態改變樣式,使用cssText(減小設置多項內聯樣式)
// bad
elem.style.left = x + "px";
elem.style.top = y + "px";
// good
elem.style.cssText += ";left: " + x + "px;top: " + y + "px;";
讓要操做的元素進行「離線處理」,處理完後一塊兒更新
當用DocumentFragment進行緩存操做,引起一次迴流和重繪
使用display:none技術,只引起兩次迴流和重繪
使用cloneNode(true or false)和replaceChild技術,引起一次迴流和重繪
不要常常訪問會引發瀏覽器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";
}
讓元素脫離動畫流,減小render tree的規模,動畫效果應用position屬性的fixed值或absolute值
儘量在DOM樹的最末端改變class,儘量在DOM樹的裏面改變class(能夠限制迴流的範圍)
犧牲平滑度換區速度
避免使用table佈局
IE中避免使用JavaScript表達式動畫

相關文章
相關標籤/搜索