實際上,DOM 大小對互動性影響的程度可能比您想像的更大。本指南將說明原因,以及您可以採取的行動。
這是無法避免的:當您建構網頁時,該網頁就會包含文件物件模型 (DOM)。DOM 代表網頁 HTML 的結構,可讓 JavaScript 和 CSS 存取網頁的結構和內容。
不過,DOM 的大小會影響瀏覽器快速且有效率地轉譯網頁的能力。一般來說,DOM 越大,初始轉譯該網頁的成本就越高,且在網頁生命週期後期更新轉譯作業的成本也會增加。
在 DOM 非常大的網頁中,如果修改或更新 DOM 的互動會觸發耗時的版面配置工作,進而影響網頁快速回應的能力,就會造成問題。耗時的版面配置作業可能會影響網頁的與下一個顯示的內容互動;如果您希望網頁能快速回應使用者互動,請務必確保 DOM 大小僅為必要的大小。
什麼時候網頁的 DOM 會「過大」?
根據 Lighthouse 的說法,如果網頁的 DOM 大小超過 1,400 個節點,就會過大。如果網頁的 DOM 超過 800 個節點,Lighthouse 就會開始發出警告。請參考以下 HTML 為例:
<ul>
<li>List item one.</li>
<li>List item two.</li>
<li>List item three.</li>
</ul>
在上述程式碼中,有四個 DOM 元素:<ul>
元素及其三個 <li>
子元素。網頁的節點數肯定會比這個數字多得多,因此請務必瞭解如何控制 DOM 大小,以及在網頁的 DOM 縮減到最小值後,如何透過其他策略最佳化轉譯作業。
大型 DOM 對網頁效能有何影響?
大型 DOM 會對網頁效能造成以下影響:
- 在網頁初始轉譯期間。將 CSS 套用至網頁時,系統會建立類似 DOM 的結構,稱為 CSS 物件模型 (CSSOM)。隨著 CSS 選取器的特定性增加,CSSOM 會變得更複雜,需要花費更多時間執行必要的版面配置、樣式、合成和繪製作業,才能將網頁繪製到畫面上。這項額外工作會增加在網頁載入初期發生的互動延遲時間。
- 當互動修改 DOM (無論是透過元素插入或刪除,或是修改 DOM 內容和樣式) 時,轉譯該更新所需的工作可能會導致版面配置、樣式、合成和繪製作業成本過高。就像網頁的初始算繪作業一樣,當 HTML 元素因互動而插入 DOM 時,CSS 選取器的特定性增加可能會增加算繪作業。
- JavaScript 查詢 DOM 時,DOM 元素的參照會儲存在記憶體中。舉例來說,如果您呼叫
document.querySelectorAll
來選取網頁上的所有<div>
元素,如果結果傳回大量 DOM 元素,記憶體成本可能會相當可觀。
![Chrome 開發人員工具「效能」面板中,因過度轉譯工作而導致的長時間工作螢幕截圖。長時間工作的呼叫堆疊記錄顯示,重新計算頁面樣式和預先繪製的時間相當長。](https://web.dev/static/articles/dom-size-and-interactivity/image/a-screenshot-a-long-task-a768ec4a643a9.png?authuser=8&hl=zh-tw)
上述所有因素都可能影響互動性,但上方清單中的第二項特別重要。如果互動導致 DOM 變更,可能會啟動大量工作,導致網頁的 INP 不佳。
如何評估 DOM 大小?
您可以透過幾種方式評估 DOM 大小。第一個方法是使用 Lighthouse。執行稽核時,「診斷」標題下方的「避免 DOM 過大」稽核會顯示目前網頁 DOM 的統計資料。在這個部分,您可以查看 DOM 元素的總數、含有最多子元素的 DOM 元素,以及最深層的 DOM 元素。
更簡單的方法是使用任何主要瀏覽器的開發人員工具中的 JavaScript 控制台。如要取得 DOM 中的 HTML 元素總數,您可以在頁面載入後,在控制台中使用下列程式碼:
document.querySelectorAll('*').length;
如果想即時查看 DOM 大小更新情形,也可以使用效能監控工具。使用這項工具,您可以將版面配置和樣式操作 (以及其他效能方面) 與目前的 DOM 大小建立關聯。
![Chrome 開發人員工具中效能監控器的螢幕截圖。在左側,您可以持續監控網頁生命週期中的各項網頁成效。在螢幕截圖中,系統正在積極監控 DOM 節點數量、每秒的版面配置數量,以及每個區段的樣式重新計算作業。](https://web.dev/static/articles/dom-size-and-interactivity/image/a-screenshot-the-perform-d46dd7f32a5de.png?authuser=8&hl=zh-tw)
如果 DOM 大小接近 Lighthouse DOM 大小的警告門檻 (或完全失敗),下一步就是瞭解如何縮減 DOM 大小,以改善網頁回應使用者互動的能力,進而提升網站的 INP。
如何評估互動影響的 DOM 元素數量?
如果您在實驗室中剖析互動速度緩慢的情況,且懷疑這與網頁 DOM 大小有關,您可以選取剖析器中標示為「Recalculate Style」的任何活動,並觀察底部面板中的內容資料,藉此瞭解有多少 DOM 元素受到影響。
![螢幕截圖:Chrome 開發人員工具效能面板中選取的樣式重新計算活動。在頂端,互動追蹤會顯示點擊互動,且大部分工作都用於樣式重新計算和預先繪製工作。底部的面板會顯示所選活動的詳細資料,其中指出有 2,547 個 DOM 元素受到影響。](https://web.dev/static/articles/dom-size-and-interactivity/image/a-screenshot-selected-st-9a6c0cc217aa3.png?authuser=8&hl=zh-tw)
請注意,在上述螢幕截圖中,選取作品的樣式重新計算功能後,畫面會顯示受影響的元素數量。雖然上述螢幕截圖顯示 DOM 大小對含有許多 DOM 元素的網頁轉譯作業的影響,但無論如何,這項診斷資訊都很實用,可用於判斷 DOM 大小是否會影響下一個影格回應互動所需的時間。
如何縮減 DOM 大小?
除了檢查網站 HTML 是否有不必要的標記,減少 DOM 深度是縮減 DOM 大小的主要方法。如果在瀏覽器開發人員工具的「Elements」分頁中看到類似以下的標記,就表示 DOM 可能過於深層:
<div>
<div>
<div>
<div>
<!-- Contents -->
</div>
</div>
</div>
</div>
當您看到這種模式時,可以透過扁平化 DOM 結構來簡化。這樣做可減少 DOM 元素數量,並可能讓您有機會簡化網頁樣式。
DOM 深度也可能是您使用的架構的症狀。特別是,以元件為基礎的架構 (例如依賴 JSX 的架構) 需要您在父項容器中巢狀放置多個元件。
不過,許多架構都允許您使用片段,避免巢狀元件。提供片段做為功能的元件式架構包括 (但不限於) 以下項目:
只要在所選架構中使用片段,即可減少 DOM 深度。如果您擔心 DOM 結構扁平化對樣式造成的影響,建議您使用更新 (且更快速) 的版面配置模式,例如 flexbox 或 grid。
其他可考慮的策略
即使您費盡心思將 DOM 樹扁平化,並移除不必要的 HTML 元素,以盡可能縮小 DOM,但 DOM 仍可能相當龐大,並會在回應使用者互動時進行大量轉譯作業。如果您發現自己處於這種情況,可以考慮採用其他策略來限制轉譯工作。
考慮採用加法式方法
您可能會遇到這樣的情況:使用者在網頁首次轉譯時,無法一開始就看到大部分的網頁內容。這可能是使用延遲載入 HTML 的機會,因為您可以在啟動時省略 DOM 的部分,但在使用者與需要網頁初始隱藏部分的網頁部分互動時,再加入這些部分。
這項做法在初始載入期間和之後都很實用。對於初始網頁載入作業,您會事先執行較少的轉譯工作,也就是說,初始 HTML 酬載會變得較輕,且轉譯速度會加快。這樣一來,在該關鍵期間內,互動作業就能有更多機會執行,且不會與主要執行緒爭奪注意力。
如果網頁的許多部分在載入時一開始就處於隱藏狀態,這麼做也能加快觸發重新算繪作業的其他互動。不過,隨著其他互動將更多內容新增至 DOM,DOM 在網頁生命週期內的規模也會增加,因此轉譯工作量也會隨之增加。
隨著時間的推移,新增 DOM 的難度會越來越高,而且會產生一些取捨。如果您採用這種做法,很可能會發出網路要求,以便取得資料,並在使用者互動時,將您想加入網頁的 HTML 填入。雖然傳輸中的網路要求不會計入 INP,但可能會增加感知延遲時間。盡可能顯示載入動畫或其他指標,讓使用者知道系統正在擷取資料,
限制 CSS 選取器的複雜度
當瀏覽器剖析 CSS 中的選取器時,必須遍歷 DOM 樹狀結構,才能瞭解這些選取器是否適用於目前的版面配置,以及如何套用。這些選取器越複雜,瀏覽器就必須執行更多工作,才能執行網頁的初始算繪作業,以及在網頁因互動而變更時,增加樣式重新計算和版面配置的工作。
使用 content-visibility
屬性
CSS 提供 content-visibility
屬性,這是一種有效的方式,可延遲轉譯畫面外的 DOM 元素。當元素接近可視區域時,系統會視需要將其算繪。content-visibility
的優點不僅可在初始網頁轉譯時大幅減少轉譯工作,還可在使用者互動導致網頁 DOM 變更時,略過轉譯畫面外元素的工作。
結論
將 DOM 大小縮減至必要的程度,是改善網站 INP 的好方法。這樣一來,您就能縮短瀏覽器在 DOM 更新時執行版面配置和轉譯作業所需的時間。即使您無法有效縮減 DOM 大小,仍可使用某些技巧將轉譯工作隔離至 DOM 子樹,例如 CSS 容器和 content-visibility
CSS 屬性。
無論您採取何種方式,只要能盡可能減少轉譯工作,並減少網頁在回應互動時所執行的轉譯工作量,使用者在與網站互動時,就會覺得網站更有回應。這表示網站的 INP 會降低,進而提供更優質的使用者體驗。