摘要:例如對于復雜動畫效果,由于會經常的引起回流重繪,因此,我們可以使用絕對定位,讓它脫離文檔流,成為一個多帶帶的圖層。
瀏覽器的渲染過程
從上面這個圖上,我們可以看到,瀏覽器渲染過程如下
解析HTML生成DOM樹,解析CSS生成CSSOM樹
將DOM樹和CSSOM樹結合生成渲染樹renderTree
Layout(回流): 根據生成的渲染樹,進行回流(Layout),得到節點的幾何信息(位置,大小)
Painting(重繪): 根據渲染樹以及回流得到的幾何信息,得到節點的絕對像素
Display:將像素發送給GPU,展示在頁面上。
生成渲染樹(RenderTree)為了構建渲染樹,瀏覽器主要完成了以下工作
從DOM樹的根節點開始遍歷每個可見節點。
對于每個可見的節點,找到CSSOM樹中對應的規則,并應用它們。
根據每個可見節點以及其對應的樣式,組合生成渲染樹。
第一步中,既然說到了要遍歷可見的節點,那么我們得先知道,什么節點是不可見的。不可見的節點包括:
一些不會渲染輸出的節點,比如script、meta、link等。
一些通過css進行隱藏的節點。比如display:none。注意,利用visibility和opacity隱藏的節點,還是會顯示在渲染樹上的。只有display:none的節點才不會顯示在渲染樹上。
回流(Layout)前面我們通過構造渲染樹,我們將可見DOM節點以及它對應的樣式結合起來,可是我們還需要計算它們在設備視口(viewport)內的確切位置和大小,這個計算的階段就是回流。
為了弄清每個對象在網站上的確切大小和位置,瀏覽器從渲染樹的根節點開始遍歷,而在回流這個階段,我們就需要根據視口具體的寬度,將其轉為實際的像素值
通過回流(Layout)階段,我們知道了所有的可見節點的樣式和具體的幾何信息(位置、大小),那么我們就可以將渲染樹的每個節點都轉換為屏幕上的實際像素,這個階段就叫做重繪節點。
何時發生回流重繪回流階段是計算節點的幾何信息和位置,那么當頁面布局或者幾何信息發生改變時,就需要回流。
添加或者刪除可見的DOM元素
元素的位置、尺寸發生變化
頁面開始渲染的時候(這肯定避免不了)
瀏覽器的視口尺寸大小發生改變(因為回流是根據瀏覽器視口的大小來計算元素的位置和尺寸大小)
注意:回流一定會觸發重繪,而重繪(非幾何信息的樣式發生改變)不一定會回流, reflow回流的成本開銷要高于repaint重繪,一個節點的回流往往回導致子節點以及同級節點的回流;
根據改變的范圍和程度,渲染樹中或大或小的部分需要重新計算,有些改變會觸發整個頁面的重排,比如,滾動條出現的時候或者修改了根節點。
基于回流(Layout)、重繪(Painting)的優化方法 避免擾亂現代瀏覽器的優化機制在現代瀏覽器的中,由于每次回流、重繪的時候,都需要額外的計算消耗,因此會通過隊列化修改,并批量執行來優化這一過程。瀏覽器會將修改操作放入隊列里面,直到過了一段時間或者達到一個閾值,才清空隊列。
但是當你獲取布局信息時,會強制刷新隊列,例如:
offsetTop、offsetLeft、offsetWidth、offsetHeight scrollTop、scrollLeft、scrollWidth、scrollHeight clientTop、clientLeft、clientWidth、clientHeight getComputedStyle() getBoundingClientRect()
上面這些方法,都需要獲取最新的布局信息,所以瀏覽器會強制刷新隊列并執行回流、重繪,來獲取最新的信息。
因此我們在修改樣式的時候,應該盡量避免使用上面的屬性、方法,如果非要使用,可以先緩存起來然后一起獲取。
考慮以下代碼
const el = document.getElementById("el") el.style.padding = "xxx" el.style.margin = "xxx" el.style.border = "xxx"
這里元素的幾何信息有三次被修改了,但是現代瀏覽器會將起緩存起來,但是如果這期間有通過前面列出來的屬性、方法訪問位置信息的話就會觸發三次回流、重繪。所以還是建議通過cssText或者class的方法一次性修改。
el.style.cssText += "border-left: 1px; border-right: 2px; padding: 5px;"; // 或者 el.className += "xxx";批量修改DOM
當我們需要對DOM進行一系列修改的時候,可以通過以下幾種方式減少回流重繪次數:
隱藏元素,應用修改,重新顯示
function appendDataToElement (appendToElement, data) { let li; for ( let i = 0; i < data.length; i++) { li = document.createElement("li"); li.textContent = "text"; appendToElement.appendChild(li); } } const ul = document.getElementById("list"); ul.style.display = "none"; // 首先脫離文檔流 appendDataToElement(ul, data); ul.style.display = "block"; // 操作完以后再可見
使用文檔片段(document fragment)在當前DOM之外構建一個子樹,再把它拷貝回文檔。
const ul = document.getElementById("list"); const fragment = document.createDocumentFragment() appendDataToElement(fragment , data); ul.appendChild(fragment )獨立圖層
一個圖層的回流和重繪只會在該圖層當中進行,不會影響其他圖層,所以有必要的時候,可以將某些元素放到多帶帶的圖層。
例如對于復雜動畫效果,由于會經常的引起回流重繪,因此,我們可以使用絕對定位,讓它脫離文檔流, 成為一個多帶帶的圖層。否則會引起父元素以及后續元素頻繁的回流。但是因該盡量少量使用圖層,因為圖層的合成是特別消耗性能,一個頁面當中不能有過多的圖層, 在使用了圖層之后需要進行前后對比
會自動建立圖層的情況:
3d或者透視變換、過渡css屬性
使用
flash
多透明度做 css動畫
其他優化用translate替代top改變: top會觸發回流,而前者不會
用opacity替代visibility: 前者回流重繪都不會觸發(前提是它多帶帶在一個圖層),后者兩個都會觸發
不要使用table布局,table的可能很小的一個改動會造成回流,很影響性能,應該盡量使用 div。
動畫實現的速度選擇:
對于動畫新建圖層
啟用GPU硬件加速: 使用transform:translateZ(0) 、transform:translate3d(0,0,0)來開啟GPU硬件加速
CSS 與 JS 是這樣阻塞 DOM 解析和渲染的通過與引入外部資源,當解析到該標簽的時候,會進行下載。
CSS腳本的加載不會阻塞 DOM 解析過程,但是會阻塞渲染過程(painting)
JS腳本的加載與執行會阻塞 DOM 解析過程, 但是不會阻塞后續資源的加載
JS腳本的加載中,如果你確定沒必要阻塞 DOM 解析的話,不妨按需要加上 defer 或者 async 屬性,此時腳本下載的過程中是不會阻塞 DOM 解析的。
瀏覽器遇到 且沒有 defer 或 async 屬性的標簽時,為了為標簽內部的js提供最新的信息,會觸發頁面的回流、重繪過程。
如果前面 CSS 資源尚未加載完畢時,瀏覽器會等待它加載完畢之后再執行腳本。即 css 不阻塞 js 的加載,但阻塞它的執行。
所以最好放底部(防止阻塞DOM解析)。最好放頭部(為渲染過程提供樣式)。如果頭部同時有與的情況下,最好將放在上面(為了防止CSS腳本加載時間過長,使js等待時間也很長)dd
defer和async直接看圖吧,綠色的代表 html 解析,藍色的代表 javascript 腳本的下載,紅色的代表 javaScript 腳本的執行。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/117134.html
摘要:所以由此來看重繪不一定導致回流,回流一定會導致重繪前面我們說回流和重繪是會對進行修改,會消耗性能,所以我們要盡可能減少回流和重繪的次數。瀏覽器自己也清楚,如果每次操作都即時地反饋一次回流或重繪,那么性能上來說是扛不住的。 回流(Reflow)重繪(Repaint) 什么時候會觸發回流或重繪呢? 當我們對dom 進行修改當時候會引發它外觀(樣式)上的改變時,就會觸發回流或重繪。這個過程本...
摘要:何時發生有大量的用戶行為以及潛在的改變會觸發回流。這樣就會讓多次的回流重繪變成一次回流重繪。因為上的操作不會引發回流和重繪。參考文章回流與重繪性能讓變慢參考文章瀏覽器的重繪與重排 推薦了解的知識:基本的HTML,基本的JavaScript,以及一些css工作原理方面的知識 瀏覽器的渲染原理 css的加載和解析不會阻塞html文檔的解析 css的解析會阻塞js的執行,必須等到CSSOM...
摘要:對于復雜動畫效果使用絕對定位讓其脫離文檔流對于復雜動畫效果,由于會經常的引起回流重繪,因此,我們可以使用絕對定位,讓它脫離文檔流。硬件加速加速比起考慮如何減少回流重繪,我們更期望的是,根本不要回流重繪。 回流和重繪可以說是每一個web開發者都經常聽到的兩個詞語,我也不例外,可是我之前一直不是很清楚這兩步具體做了什么事情。最近由于部門內部要做分享,所以對其進行了一些研究,看了一些博客和書...
摘要:否則會引起父元素以及后續元素頻繁的回流。硬件加速加速硬件加速加速比起考慮如何減少回流重繪,我們更期望的是,根本不要回流重繪。這個時候,硬件加速就閃亮登場啦劃重點使用硬件加速,可以讓這些動畫不會引起回流重繪。回流和重繪可以說是每一個web開發者都經常聽到的兩個詞語,我也不例外,可是一直不是很清楚這兩步具體做了什么事情。最近由于部門內部要做分享,所以對其進行了一些研究,看了一些博客和書籍,整理了...
摘要:硬件加速加速比起考慮如何減少回流重繪,我們更期望的是,根本不要回流重繪。這個時候,硬件加速就閃亮登場啦劃重點使用硬件加速,可以讓這些動畫不會引起回流重繪。 本文由云+社區發表 回流和重繪可以說是每一個web開發者都經常聽到的兩個詞語,可是可能有很多人不是很清楚這兩步具體做了什么事情。最近有空對其進行了一些研究,看了一些博客和書籍,整理了一些內容并且結合一些例子,寫了這篇文章,希望可以幫...
閱讀 999·2019-08-30 15:55
閱讀 3440·2019-08-30 13:10
閱讀 1267·2019-08-29 18:45
閱讀 2346·2019-08-29 16:25
閱讀 2106·2019-08-29 15:13
閱讀 2421·2019-08-29 11:29
閱讀 551·2019-08-26 17:34
閱讀 1485·2019-08-26 13:57