本文首發於個人我的網站: litgod.net
以前面試的大佬問我關於重排重繪的原理和具體操做,一會兒把我問蒙了。回家便默默地把問題記下來,仔細總結……在閱讀了一些文章後,本身也有了必定的理解,因此分享給你們。但願你們也能耐心把這篇文章看完,認真思考,完全掌握這個知識點!css
1.HTML 被 HTML 解析器解析成 DOM 樹;
2.CSS 被 CSS 解析器解析成 CSSOM 樹;
3.結合 DOM 樹和 CSSOM 樹,生成一棵渲染樹(Render Tree),這一過程稱爲 Attachment;
4.生成佈局(flow),瀏覽器在屏幕上「畫」出渲染樹中的全部節點;
5.將佈局繪製(paint)在屏幕上,顯示出整個頁面。html
第四步和第五步是最耗時的部分,這兩步合起來,就是咱們一般所說的渲染。前端
在頁面的生命週期中,網頁生成的時候,至少會渲染一次。在用戶訪問的過程當中,還會不斷觸發重排(reflow)和重繪(repaint),無論頁面發生了重繪仍是重排,都會影響性能,最可怕的是重排,會使咱們付出高額的性能代價,因此咱們應儘可能避免。面試
大,在這個語境裏的意思是:誰能影響誰?segmentfault
就如上面的概念同樣,單單改變元素的外觀,確定不會引發網頁從新生成佈局,但當瀏覽器完成重排以後,將會從新繪製受到這次重排影響的部分。好比改變元素高度,這個元素乃至周邊dom都須要從新繪製。瀏覽器
也就是說:重繪不必定致使重排,但重排必定會致使重繪。緩存
當DOM的變化影響了元素的幾何信息(元素的的位置和尺寸大小),瀏覽器須要從新計算元素的幾何屬性,將其安放在界面中的正確位置,這個過程叫作重排。網絡
重排也叫回流,簡單的說就是從新生成佈局,從新排列元素。dom
:hover
)getComputedStyle
方法,或者IE裏的 currentStyle
時,也會觸發重排,原理是同樣的,都爲求一個「即時性」和「準確性」。常見引發重排屬性和方法 | -- | -- | -- |
---|---|---|---|
width | height | margin | padding |
display | border-width | border | position |
overflow | font-size | vertical-align | min-height |
clientWidth | clientHeight | clientTop | clientLeft |
offsetWudth | offsetHeight | offsetTop | offsetLeft |
scrollWidth | scrollHeight | scrollTop | scrollLeft |
scrollIntoView() | scrollTo() | getComputedStyle() | |
getBoundingClientRect() | scrollIntoViewIfNeeded() |
因爲瀏覽器渲染界面是基於流失佈局模型的,因此觸發重排時會對周圍DOM從新排列,影響的範圍有兩種:ide
全局範圍重排:
<body> <div class="hello"> <h4>hello</h4> <p><strong>Name:</strong>BDing</p> <h5>male</h5> <ol> <li>coding</li> <li>loving</li> </ol> </div> </body>
當p節點上發生reflow時,hello和body也會從新渲染,甚至h5和ol都會收到影響。
局部範圍重排:
用局部佈局來解釋這種現象:把一個dom的寬高之類的幾何信息定死,而後在dom內部觸發重排,就只會從新渲染該dom內部的元素,而不會影響到外界。
當一個元素的外觀發生改變,但沒有改變佈局,從新把元素外觀繪製出來的過程,叫作重繪。
屬性: | -- | -- | -- |
---|---|---|---|
color | border-style | visibility | background |
text-decoration | background-image | background-position | background-repeat |
outline-color | outline | outline-style | border-radius |
outline-width | box-shadow | background-size |
重排的代價是高昂的,會破壞用戶體驗,而且讓UI展現很是遲緩。經過減小重排的負面影響來提升用戶體驗的最簡單方式就是儘量的減小重排次數,重排範圍。下面是一些行之有效的建議,你們能夠用來參考。
咱們應該儘可能以局部佈局的形式組織html結構,儘量小的影響重排的範圍。
不要頻繁的操做樣式,對於一個靜態頁面來講,明智且可維護的作法是更改類名而不是修改樣式,對於動態改變的樣式來講,相較每次微小修改都直接觸及元素,更好的辦法是統一在 cssText
變量中編輯。雖然如今大部分現代瀏覽器都會有 Flush
隊列進行渲染隊列優化,可是有些老版本的瀏覽器好比IE6的效率依然低下。
// bad var left = 10; var top = 10; el.style.left = left + "px"; el.style.top = top + "px"; // 當top和left的值是動態計算而成時... // better el.style.cssText += "; left: " + left + "px; top: " + top + "px;"; // better el.className += " className";
DOM 的多個讀操做(或多個寫操做),應該放在一塊兒。不要兩個讀操做之間,加入一個寫操做。
// bad 強制刷新 觸發四次重排+重繪 div.style.left = div.offsetLeft + 1 + 'px'; div.style.top = div.offsetTop + 1 + 'px'; div.style.right = div.offsetRight + 1 + 'px'; div.style.bottom = div.offsetBottom + 1 + 'px'; // good 緩存佈局信息 至關於讀寫分離 觸發一次重排+重繪 var curLeft = div.offsetLeft; var curTop = div.offsetTop; var curRight = div.offsetRight; var curBottom = div.offsetBottom; div.style.left = curLeft + 1 + 'px'; div.style.top = curTop + 1 + 'px'; div.style.right = curRight + 1 + 'px'; div.style.bottom = curBottom + 1 + 'px';
原來的操做會致使四次重排,讀寫分離以後實際上只觸發了一次重排,這都得益於瀏覽器的渲染隊列機制:
當咱們修改了元素的幾何屬性,致使瀏覽器觸發重排或重繪時。它會把該操做放進渲染隊列,等到隊列中的操做到了必定的數量或者到了必定的時間間隔時,瀏覽器就會批量執行這些操做。
「離線」意味着不在當前的 DOM 樹中作修改,咱們能夠這樣作:
一旦咱們給元素設置 display:none
時(只有一次重排重繪),元素便不會再存在在渲染樹中,至關於將其從頁面上「拿掉」,咱們以後的操做將不會觸發重排和重繪,添加足夠多的變動後,經過 display
屬性顯示(另外一次重排重繪)。經過這種方式即便大量變動也只觸發兩次重排。另外,visibility : hidden
的元素只對重繪有影響,不影響重排。
dom
碎片,在它上面批量操做 dom
,操做完成以後,再添加到文檔中,這樣只會觸發一次重排。使用絕對定位會使的該元素單獨成爲渲染樹中 body
的一個子元素,重排開銷比較小,不會對其它節點形成太多影響。當你在這些節點上放置這個元素時,一些其它在這個區域內的節點可能須要重繪,可是不須要重排。
position
屬性爲 absolute
或 fixed
的元素上,這樣對其餘元素影響較小。動畫效果還應犧牲一些平滑,來換取速度,這中間的度本身衡量:
好比實現一個動畫,以1個像素爲單位移動這樣最平滑,可是Layout就會過於頻繁,大量消耗CPU資源,若是以3個像素爲單位移動則會好不少
GPU
硬件加速是指應用 GPU
的圖形性能對瀏覽器中的一些圖形操做交給 GPU
來完成,由於 GPU
是專門爲處理圖形而設計,因此它在速度和能耗上更有效率。GPU
加速一般包括如下幾個部分:Canvas2D,佈局合成, CSS3轉換(transitions),CSS3 3D變換(transforms),WebGL和視頻(video)。
1.打開開發者工具:點擊 Performance 左側有個小圓點 點擊刷新頁面會錄製整個頁面加載出來 時間的分配狀況。以下圖
哪一種色塊比較多,就說明性能耗費在那裏。色塊越長,問題越大。
2.點擊 Event Log:單獨勾選 Loading 項會顯示 html 和 css 加載時間。以下圖:
3.解析完 DOM+CSSOM 以後會生成一個渲染樹 Render Tree,就是 DOM 和 CSSOM 的一一對應關係。
4.經過渲染樹中在屏幕上「畫」出的全部節點,稱爲渲染。
很是感謝你看完了這篇很長的文章,也但願你們能重視重排的這些問題,在咱們平時的開發中,也須要有意識的規避這些問題,才能讓咱們寫出來的代碼更規範!
掌握瀏覽器重繪(repaint)重排(reflow))-前端進階
csstriggers
CSS硬件加速的好與壞