Chrome 開發人員工具開始支援頂層元素,方便開發人員對使用頂層元素的程式碼進行偵錯。
本文將說明什麼是頂層元素、開發人員工具如何以視覺化方式呈現頂層內容,進而瞭解含有頂層元素的 DOM 結構,並進行偵錯。
頂層和頂層元素是什麼?
以互動形式開啟 <dialog>
時,內部會發生什麼情況?🤔
放在頂層頂層內容會顯示在所有其他內容上方。舉例來說,強制回應對話方塊必須顯示在所有其他 DOM 內容上方,因此瀏覽器會自動將這個元素轉譯至「頂層」,而不是強迫作者手動對 Z-index 進行對戰。即使 Z-index 值最高,頂層圖層元素仍會顯示在元素上方。
頂層資料層可解釋為「最高堆疊層」。每份文件都會有一個相關聯的可視區域,因此也會是單一頂層。多個元素可以同時在頂層圖層內。發生這種情況時,狀態會堆疊在最後一列,換句話說,所有頂層元素都會放置在頂層「最後一級」、「先出入」 (LIFO) 堆疊中。
<dialog>
元素不是瀏覽器要在頂層算繪的元素。目前的頂層元素包括:彈出式視窗、強制回應對話方塊和全螢幕模式的元素。
檢查下列對話方塊實作方式:
<main>
<button onclick="window.dialog.showModal();">Open Dialog</button>
</main>
<dialog id="dialog"></dialog>
下方為示範,當中有幾個對話方塊的樣式已套用至背景 (如下所述):
什麼是背景?
幸好,您可以自訂頂層元素底下的內容。
頂層的每個元素都有稱為「背景」的 CSS 虛擬元素。
「背景幕」是可視區域的大小方塊,會顯示在任何頂層元素下方。::backdrop
虛擬元素是頂層元素中最頂層的元素時,導致元素下方的所有元素遭到遮蓋、樣式或完全隱藏。
將多個元素設為互動視窗時,瀏覽器會立刻繪製背景,位於等最前方的元素下方和其他全螢幕元素的上方。
以下是設定背景幕的樣式:
/* The browser displays the backdrop only when the dialog.showModal() function opens the dialog.*/
dialog::backdrop {
background: rgba(255,0,0,.25);
}
如何只顯示第一個背景?
每個頂層元素都有屬於頂層堆疊的背景。這些背景的設計會彼此重疊,因此如果背景的不透明度不是 100%,就能顯示後方的背景。
如果只需要顯示頂層堆疊中的第一個背景,只要在頂層堆疊中追蹤項目 ID,即可達成這個目標。
如果新增的元素不是頂層圖層的第一個元素,當元素放入頂層圖層時呼叫的函式,就會將 hiddenBackdrop
類別套用至 ::backdrop
。從頂層圖層移除元素時,會移除該類別。
請查看這個範例中的程式碼:
開發人員工具的頂層支援設計
頂層開發人員工具支援可協助開發人員瞭解頂層內容的概念,並以視覺化的方式呈現頂層內容的變化。這些功能可協助開發人員識別下列項目:
- 頂層圖層中的元素及其順序隨時皆可。
- 堆疊頂端的任何時間點的元素。
此外,開發人員工具頂層支援可協助您以視覺化方式呈現在頂層堆疊中,背景虛擬元素的位置。雖然這並非樹狀結構元素,但對頂層層的運作方式來說仍扮演重要角色,這對開發人員來說相當實用。
有了頂層支援功能,您可以:
- 隨時觀察哪些元素位於頂層堆疊。在上層圖層新增或移除元素時,頂層表示法堆疊會動態調整。
- 查看元素在頂層堆疊中的位置。
- 從樹狀結構的頂層元素或元素的背景虛擬元素,跳至頂層表示法容器中的元素或背景虛擬元素。
讓我們一起瞭解如何使用這些功能!
頂層容器
為了以視覺化方式呈現頂層元素,開發人員工具會在元素樹狀結構中加入頂層容器。位於 </html>
結尾標記後方。
這個容器可隨時觀察頂層堆疊中的元素。頂層容器提供頂層元素及其背景的連結清單。在上層圖層新增或移除元素時,頂層表示法堆疊會動態調整。
如要在元素樹狀結構或頂層容器內尋找頂層元素,請點選頂端圖層容器中頂層元素表示法的連結,前往元素樹狀結構中與先前相同的元素。
如要從頂層容器元素跳到頂層樹狀結構元素,請在頂層容器中點選元素旁邊的「顯示」按鈕。
如要從頂層樹狀結構元素跳至頂層容器中的連結,請按一下元素旁的頂層徽章。
您可以停用任何徽章,包括頂層標記。如要停用徽章,請在任一徽章上按一下滑鼠右鍵,選擇「徽章設定」,並清除要隱藏的徽章旁邊的勾號。
頂層堆疊中的元素順序
頂層容器會顯示元素在堆疊中的顯示方式,但順序相反。堆疊元素的頂端是頂層容器的元素清單的最後一個位置。也就是說,頂層容器清單中的最後一個元素是您目前可以在文件中互動的元素。
樹狀結構元素旁的標記會指出元素是否屬於頂層,並包含堆疊中元素的位置數量。
在這個螢幕截圖中,頂層堆疊包含兩個元素,第二個元素位於堆疊頂端。如果移除第二個元素,第一個元素會移至頂端。
頂層容器中的背景幕
如前所述,每個頂層元素都有稱為「背景」的 CSS 虛擬元素。您可以為這個元素設定樣式,因此也很適合用來檢查該元素並查看其呈現方式。
在元素樹狀結構中,背景元素位於其所屬元素的結尾標記之前。然而,在頂層容器中,背景連結會列在所屬頂層元素的上方。
DOM 樹狀結構的變更
ElementsTreeElement
(負責在開發人員工具中建立及管理個別 DOM 樹狀結構元素的類別) 不足以實作頂層容器。
為了在樹狀結構中將頂層容器顯示為節點,我們新增了可建立開發人員工具樹狀結構元素節點的類別。先前負責建立開發人員工具元素樹狀結構的類別,會使用 DOMNode
初始化每個 TreeElement
,該類別包含 backendNodeId
及其他後端相關屬性。backendNodeId
隨後會在後端指派。
頂層容器節點含有頂層元素連結清單,需要像一般樹狀結構元素節點一樣運作。然而,這個節點不是「實際」的 DOM 節點,後端也不需要建立頂層容器節點。
為建立代表頂層的前端節點,我們新增了在沒有 DOMNode
的情況下建立的新型前端節點。這個頂層容器元素是第一個沒有 DOMNode
的前端節點,也就是只存在於前端,而後端不會知道。為了讓行為與其他節點相同,我們建立新的 TopLayerContainer
類別,可擴充 UI.TreeOutline.TreeElement
類別,該類別負責前端節點的行為。
為達到需要的位置,算繪元素的類別會附加 TopLayerContainer
,做為下一個 <html>
標記的同層。
新的頂層標記會指出該元素位於頂層,而且是 TopLayerContainer
元素中此元素的捷徑連結。
初始設計
預計一開始,計劃將頂層元素複製到頂層容器,而非建立元素連結清單。由於在開發人員工具中擷取元素子項的方式,我們未實作這項解決方案。每個元素都有一個用於擷取子項的父項指標,因此無法有多個指標。因此,我們無法在樹狀結構的多個位置設定適當展開並包含所有子項的節點。一般來說,系統不會在建構系統時考量重複的子樹狀結構。
我們遇到的入侵是建立連至前端 DOM 節點的連結,而不是複製這些節點。在開發人員工具中建立元素連結的類別為 ShortcutTreeElement
,該類別會擴充 UI.TreeOutline.TreeElement
。ShortcutTreeElement
的行為與其他開發人員工具 DOM 樹狀結構元素相同,但在後端沒有對應節點,且具有連結至 ElementsTreeElement
的按鈕。每個頂層節點的 ShortcutTreeElement
都有子項 ShortcutTreeElement
,可連結至開發人員工具 DOM 樹狀結構中 ::backdrop
虛擬元素的表示法。
初始設計:
Chrome 開發人員工具通訊協定 (CDP) 異動
如要導入頂層支援機制,您必須變更 Chrome 開發人員工具通訊協定 (CDP)。CDP 做為開發人員工具和 Chromium 之間的通訊協定。
我們需要新增下列項目:
- 隨時可以從前端呼叫的指令。
- 要從後端在前端觸發的事件。
CDP:DOM.getTopLayerElements
指令
我們需要新的實驗性 CDP 指令,傳回頂層元素的節點 ID 清單,才能顯示目前的頂層元素。每當開發人員工具開啟或頂層元素變更時,開發人員工具就會呼叫這個指令。這個指令如下所示:
# Returns NodeIds of the current top layer elements.
# Top layer renders closest to the user within a viewport, therefore, its elements always
# appear on top of all other content.
experimental command getTopLayerElements
returns
# NodeIds of the top layer elements.
array of NodeId nodeIds
CDP:DOM.topLayerElementsUpdated
事件
若要取得最新的頂層元素清單,我們需要每次變更頂層元素,才能觸發實驗性 CDP 事件。這個事件會將變更告知前端,然後呼叫 DOM.getTopLayerElements
指令並接收新的元素清單。
事件看起來會像這樣:
# Called by the change of the top layer elements.
experimental event topLayerElementsUpdated
CDP 注意事項
有幾個選項可決定如何實作頂層 CDP 支援功能。另一個我們認為的選項,是在製作會傳回頂層元素清單的事件,而不只是通知前端元素新增或移除頂層元素。
或者,我們也可以建立兩個事件,而不是指令:topLayerElementAdded
和 topLayerElementRemoved
。在這個範例中,我們會收到 元素,且需要管理前端元素的陣列。
目前,前端事件會呼叫 getTopLayerElements
指令來取得更新後的元素清單。如果我們在每次觸發事件時,就傳送導致變更的元素清單或特定元素清單,可能會避免呼叫該指令的步驟。
不過在這種情況下,前端無法控制要推送哪些元素。
我們之所以以這種方式實作,是因為就本質而言,如果前端決定要求頂層節點的情況會更好。舉例來說,如果 UI 中收合頂層圖層,或是使用者使用的開發人員工具面板沒有元素樹狀結構,就不需要取得更深入的樹狀結構。