關鍵渲染路徑
關鍵渲染路徑是瀏覽器將 HTML、CSS 和 JavaScript 轉換為螢幕畫素所經歷的步驟序列。最佳化關鍵渲染路徑可以提升渲染效能。關鍵渲染路徑包括 文件物件模型 (DOM)、CSS 物件模型 (CSSOM)、渲染樹和佈局。
在解析 HTML 時,會建立文件物件模型。HTML 可能請求 JavaScript,而 JavaScript 又可能修改 DOM。HTML 包含或請求樣式,然後構建 CSS 物件模型。瀏覽器引擎將兩者結合起來建立渲染樹。佈局決定了頁面上所有元素的尺寸和位置。一旦確定了佈局,畫素就會被繪製到螢幕上。
最佳化關鍵渲染路徑可縮短首次渲染時間。理解和最佳化關鍵渲染路徑對於確保每秒 60 幀的重排和重繪,確保高效能的使用者互動,以及避免卡頓至關重要。
理解 CRP
Web 效能包括伺服器請求和響應、載入、指令碼、渲染、佈局以及畫素繪製到螢幕的整個過程。
對網頁或應用程式的請求始於 HTTP 請求。伺服器傳送包含 HTML 的響應。然後瀏覽器開始解析 HTML,將接收到的位元組轉換為 DOM 樹。每次瀏覽器發現外部資源的連結時,無論是樣式表、指令碼還是嵌入的影像引用,它都會發起請求。有些請求是阻塞的,這意味著解析其餘 HTML 會暫停,直到匯入的資源被處理。瀏覽器繼續解析 HTML,進行請求並構建 DOM,直到到達末尾,此時它會構建 CSS 物件模型。在 DOM 和 CSSOM 完成後,瀏覽器會構建渲染樹,計算所有可見內容的樣式。渲染樹完成後,就會發生布局,定義渲染樹中所有元素的位置和大小。完成後,頁面就會在螢幕上渲染或“繪製”。
文件物件模型
DOM 構建是增量的。HTML 響應會變成標記,標記會變成節點,節點會變成 DOM 樹。單個 DOM 節點以 startTag 標記開始,以 endTag 標記結束。節點包含有關 HTML 元素的所有相關資訊。資訊透過標記進行描述。節點根據標記的層級結構連線成 DOM 樹。如果在某一對 startTag 和 endTag 標記之間出現了另一對 startTag 和 endTag 標記,那麼你就有一個節點包含另一個節點,這就是我們定義 DOM 樹層級結構的方式。
節點數量越多,關鍵渲染路徑中後續事件的耗時就越長。進行測量!少幾個節點不會造成太大影響,但請記住,新增大量額外節點會影響效能。
CSS 物件模型
DOM 包含頁面的所有內容。CSSOM 包含有關如何設定 DOM 樣式的全部資訊。CSSOM 與 DOM 類似,但有所不同。雖然 DOM 構建是增量的,但 CSSOM 不是。CSS 會阻塞渲染:瀏覽器會阻止頁面渲染,直到收到並處理完所有 CSS。CSS 會阻塞渲染,因為規則可能會被覆蓋,所以直到 CSSOM 完成後才能渲染內容。
CSS 有自己的一套規則來識別有效標記。請記住,CSS 中的 C 代表“級聯”(Cascade)。CSS 規則向下級聯。當解析器將標記轉換為節點時,子節點將繼承父節點的一些樣式。增量處理功能不適用於 CSS,而適用於 HTML,因為後續規則可能會覆蓋之前的規則。CSS 物件模型在解析 CSS 時構建,但直到完全解析後才能用於構建渲染樹,因為將要被後續解析覆蓋的樣式不應被渲染到螢幕上。
在選擇器效能方面,不那麼具體的選擇器比更具體的選擇器快。例如,.foo {} 比 .bar .foo {} 快,因為在第二種情況下,當瀏覽器找到 .foo 時,它必須向上遍歷 DOM 以檢查 .foo 是否有父級 .bar。更具體的標籤需要瀏覽器做更多的工作,但這種效能損失可能不值得去最佳化。
如果您測量解析 CSS 所需的時間,您會驚訝於瀏覽器的速度。更具體的規則成本更高,因為它必須遍歷 DOM 樹中的更多節點——但這種額外的成本通常很小。首先進行測量。然後根據需要進行最佳化。特異性可能不是您最容易解決的效能瓶頸。就 CSS 而言,選擇器效能最佳化改進只會帶來微秒級的提升。還有最佳化 CSS 的其他方法,例如縮小化,以及使用媒體查詢將延遲載入的 CSS 分離為非阻塞請求。
渲染樹
渲染樹同時捕獲內容和樣式:DOM 和 CSSOM 樹被合併到渲染樹中。為了構建渲染樹,瀏覽器從 DOM 樹的根開始檢查每個節點,並確定哪些 CSS 規則已附加。
渲染樹只捕獲可見內容。head 部分(通常)不包含任何可見資訊,因此不包含在渲染樹中。如果元素上設定了 display: none;,那麼它本身及其所有後代都不會包含在渲染樹中。
佈局
渲染樹構建完成後,佈局就成為可能。佈局取決於螢幕大小。佈局步驟決定了元素在頁面上的位置和方式,確定每個元素的寬度和高度,以及它們之間的關係。
元素的寬度是多少?塊級元素,顧名思義,其預設寬度為其父元素寬度的 100%。寬度為 50% 的元素將是其父元素寬度的一半。除非另有定義,否則 body 的寬度為 100%,這意味著它將是視口寬度的 100%。裝置的寬度會影響佈局。
視口元標籤定義了佈局視口的寬度,從而影響佈局。沒有它,瀏覽器將使用預設視口寬度,在預設全屏瀏覽器中通常為 960px。在預設全屏瀏覽器(如手機瀏覽器)中,透過設定 <meta name="viewport" content="width=device-width">,寬度將是裝置的寬度,而不是預設視口寬度。當用戶在橫屏和豎屏模式之間旋轉手機時,裝置寬度會發生變化。每次裝置旋轉或瀏覽器調整大小時都會發生布局。
佈局效能受 DOM 的影響——節點數量越多,佈局所需的時間就越長。佈局可能成為瓶頸,如果它在滾動或其他動畫期間被需要,就會導致卡頓。雖然載入或方向更改時的 20ms 延遲可能沒問題,但在動畫或滾動時會導致卡頓。任何時候渲染樹被修改,例如透過新增節點、更改內容或更新節點的盒模型樣式,都會發生布局。
為了減少佈局事件的頻率和持續時間,請批處理更新並避免對盒模型屬性進行動畫處理。
繪製
最後一步是將畫素繪製到螢幕上。一旦建立了渲染樹併發生了佈局,就可以將畫素繪製到螢幕上。載入時,整個螢幕都會被繪製。之後,只有受影響的螢幕區域會被重繪,因為瀏覽器經過最佳化,只需重繪所需的最小區域。繪製時間取決於應用於渲染樹的更新型別。雖然繪製是一個非常快速的過程,因此很可能不是提高效能的最有影響力的環節,但重要的是要記住,在衡量動畫幀需要多長時間時,要同時考慮佈局和重繪時間。應用於每個節點的樣式會增加繪製時間,但移除會使繪製時間增加 0.001 毫秒的樣式可能不會為您帶來最大的最佳化效益。請記住先進行測量。然後您就可以確定這是否應成為最佳化重點。
為 CRP 進行最佳化
透過優先載入哪些資源、控制載入順序以及減小資原始檔大小來提高頁面載入速度。效能技巧包括 1) 透過延遲載入非關鍵資源、將其標記為非同步或完全消除它們來最小化關鍵資源的數量,2) 最佳化所需的請求數量以及每個請求的檔案大小,以及 3) 透過優先下載關鍵資產來最佳化關鍵資源的載入順序,從而縮短關鍵路徑長度。