Supporto di livello superiore in Chrome DevTools

Strumenti per sviluppatori di Chrome aggiunge il supporto per gli elementi di primo livello, semplificando il debug del codice che li utilizza.

Questo articolo descrive che cosa sono gli elementi di primo livello, in che modo DevTools aiutano a visualizzare i contenuti di primo livello per comprendere e eseguire il debug della struttura DOM che contiene gli elementi di primo livello e come viene implementato il supporto del primo livello di DevTools.

Che cosa sono il livello superiore e gli elementi del livello superiore?

Che cosa succede esattamente internamente quando apri un <dialog> come finestra modale? 🤔

Viene inserito in un livello superiore. I contenuti del livello superiore vengono visualizzati sopra tutti gli altri contenuti. Ad esempio, una finestra di dialogo modale deve essere visualizzata sopra tutti gli altri contenuti DOM, quindi il browser esegue automaticamente il rendering di questo elemento in un "livello superiore" anziché costringere gli autori a gestire manualmente l'indice z. Un elemento del livello superiore viene visualizzato sopra un elemento anche con l'indice z più alto.

Il livello superiore può essere descritto come "il livello di impilamento più alto". Ogni documento ha un solo viewport associato e, di conseguenza, anche un solo livello superiore. All'interno del livello superiore possono essere presenti più elementi contemporaneamente. In questo caso, si impilano l'uno sull'altro, con l'ultimo in cima. In altre parole, tutti gli elementi del livello superiore vengono inseriti in una pila last in, first out (LIFO) nel livello superiore.

L'elemento <dialog> non è l'unico elemento visualizzato dal browser in un livello superiore. Attualmente, gli elementi del livello superiore sono: popover, finestre di dialogo modali ed elementi in modalità a schermo intero.

Esamina la seguente implementazione della finestra di dialogo:

<main>
  <button onclick="window.dialog.showModal();">Open Dialog</button>
</main>
<dialog id="dialog"></dialog>

Ecco una demo con un paio di finestre di dialogo a cui sono stati applicati stili agli sfondi (descritti di seguito):

Che cos'è uno sfondo?

Fortunatamente, esiste un modo per personalizzare i contenuti sotto l'elemento del livello superiore.

Ogni elemento del livello superiore ha uno pseudo-elemento CSS chiamato backdrop.

Lo sfondo è una casella delle dimensioni dell'area visibile che viene visualizzata immediatamente sotto qualsiasi elemento del livello superiore. Lo pseudo-elemento ::backdrop consente di oscurare, applicare uno stile o nascondere completamente tutto ciò che si trova sotto l'elemento quando è quello più in alto nel livello superiore.

Quando rendi modali più elementi, il browser disegna lo sfondo immediatamente sotto l'elemento in primo piano e sopra gli altri elementi a schermo intero.

Ecco come applicare uno stile a uno sfondo:

/* The browser displays the backdrop only when the dialog.showModal() function opens the dialog.*/
dialog::backdrop {
    background: rgba(255,0,0,.25);
}

Come faccio a mostrare solo il primo sfondo?

Ogni elemento del livello superiore ha uno sfondo che appartiene a una serie di livelli superiori. Questi sfondi sono progettati per sovrapporsi, quindi se l'opacità di uno sfondo non è del 100%, gli sfondi sottostanti sono visibili.

Se deve essere visibile solo il primo sfondo nello stack del livello superiore, puoi farlo monitorando gli identificatori degli elementi nello stack del livello superiore.

Se l'elemento aggiunto non è il primo nel livello superiore, la funzione chiamata quando l'elemento viene inserito nel livello superiore applica una classe hiddenBackdrop a ::backdrop. Questa classe viene rimossa quando l'elemento viene rimosso dal livello superiore.

Dai un'occhiata al codice in questa demo di esempio:

Progettazione del supporto del livello superiore in DevTools

Il supporto di DevTools per il livello superiore aiuta gli sviluppatori a comprendere il concetto del livello superiore e a visualizzare la modifica dei contenuti del livello superiore. Queste funzionalità aiutano gli sviluppatori a identificare quanto segue:

  • Gli elementi nel livello superiore in qualsiasi momento e il relativo ordine.
  • L'elemento nella parte superiore della pila in qualsiasi momento.

Inoltre, il supporto del livello superiore di DevTools consente di visualizzare la posizione dell'elemento pseudo-sfondo nello stack del livello superiore. Anche se non è un elemento dell'albero, svolge un ruolo importante nel funzionamento del livello superiore e può essere utile per gli sviluppatori.

Con le funzionalità di assistenza del livello superiore, puoi:

  1. Osserva in qualsiasi momento quali elementi sono presenti nella pila del livello superiore. La serie di rappresentazioni del livello superiore cambia dinamicamente man mano che gli elementi vengono aggiunti o rimossi dal livello superiore.
  2. Visualizza la posizione dell'elemento nell'elenco di livelli superiore.
  3. Passa dall'elemento o dagli pseudo-elementi di sfondo del livello superiore nell'albero all'elemento o allo pseudo-elemento di sfondo nel contenitore di rappresentazione del livello superiore e viceversa.

Vediamo come utilizzare queste funzionalità.

Contenitore del livello superiore

Per facilitare la visualizzazione degli elementi del livello superiore, DevTools aggiunge un contenitore del livello superiore all'albero degli elementi. Si trova dopo il tag di chiusura </html>.

Questo contenitore ti consente di osservare gli elementi nello stack del livello superiore in qualsiasi momento. Il contenitore del livello superiore è un elenco di link agli elementi del livello superiore e ai relativi sfondi. La serie di rappresentazioni del livello superiore cambia dinamicamente man mano che gli elementi vengono aggiunti o rimossi dal livello superiore.

Per trovare gli elementi del livello superiore all'interno dell'albero degli elementi o del contenitore del livello superiore, fai clic sui link dalla rappresentazione dell'elemento del livello superiore nel contenitore del livello superiore allo stesso elemento nell'albero degli elementi e viceversa.

Per passare dall'elemento contenitore del livello superiore all'elemento dell'albero del livello superiore, fai clic sul pulsante Mostra accanto all'elemento nel contenitore del livello superiore.

Passaggio dal link del contenitore del livello superiore all&#39;elemento.

Per passare dall'elemento dell'albero del livello superiore al link nel contenitore del livello superiore, fai clic sul badge livello superiore accanto all'elemento.

Passaggio da un elemento al link del contenitore del livello superiore.

Puoi disattivare qualsiasi badge, incluso quello del livello superiore. Per disattivare i badge, fai clic con il tasto destro del mouse su un badge, scegli Impostazioni badge e deseleziona i badge che vuoi nascondere.

Disattiva il badge.

Ordine degli elementi nella pila del livello superiore

Il contenitore del livello superiore mostra gli elementi così come appaiono nella serie, ma in ordine inverso. L'elemento più in alto della pila è l'ultimo nell'elenco di elementi del contenitore del livello superiore. Ciò significa che l'ultimo elemento nell'elenco dei contenitori del livello superiore è l'elemento con cui puoi interagire al momento nel documento.

I badge accanto agli elementi dell'albero indicano se gli elementi appartengono al livello superiore e contengono il numero di posizione di un elemento nella pila.

In questo screenshot, la pila del livello superiore è composta da due elementi, con il secondo elemento in cima alla pila. Se rimuovi il secondo elemento, il primo viene spostato in alto.

L&#39;ordine degli elementi nell&#39;elenco.

Sfondi nel contenitore del livello superiore

Come accennato in precedenza, ogni elemento del livello superiore ha uno pseudo-elemento CSS chiamato backdrop. Poiché puoi applicare uno stile a questo elemento, è utile anche ispezionarlo e visualizzarne la rappresentazione.

Nella struttura ad albero degli elementi, un elemento di sfondo si trova prima del tag di chiusura dell'elemento a cui appartiene. Tuttavia, nel contenitore del livello superiore, un link sfondo è elencato proprio sopra l'elemento del livello superiore a cui appartiene.

Posizione dell&#39;elenco di sfondo.

Modifiche all'albero DOM

ElementsTreeElement, la classe responsabile della creazione e della gestione dei singoli elementi dell'albero DOM in DevTools, non era sufficiente per implementare un contenitore di primo livello.

Per visualizzare il contenitore del livello superiore come un nodo nella struttura ad albero, abbiamo aggiunto una nuova classe che crea i nodi degli elementi della struttura ad albero di DevTools. In precedenza, la classe responsabile della creazione dell'albero degli elementi di DevTools inizializzava ogni TreeElement con un DOMNode, ovvero una classe con un backendNodeId e altre proprietà relative al backend. backendNodeId, a sua volta, viene assegnato nel backend.

Il nodo contenitore del livello superiore, che contiene un elenco di link agli elementi del livello superiore, doveva comportarsi come un normale nodo elemento dell'albero. Tuttavia, questo nodo non è un nodo DOM "reale" e il backend non deve creare il nodo contenitore del livello superiore.

Per creare un nodo frontend che rappresenti il livello superiore, abbiamo aggiunto un nuovo tipo di nodo frontend che viene creato senza un DOMNode. Questo elemento contenitore del livello superiore è il primo nodo frontend che non ha un DOMNode, il che significa che esiste solo sul frontend e il backend non lo "conosce". Per avere lo stesso comportamento degli altri nodi, abbiamo creato una nuova classe TopLayerContainer che estende la classe UI.TreeOutline.TreeElement responsabile del comportamento dei nodi frontend.

Per ottenere il posizionamento desiderato, la classe che esegue il rendering di un elemento associa TopLayerContainer come elemento successivo del tag <html>.

Un nuovo badge del livello superiore indica che l'elemento si trova nel livello superiore e funge da link alla scorciatoia di questo elemento nell'elemento TopLayerContainer.

Progettazione iniziale

Inizialmente, il piano era quello di duplicare gli elementi del livello superiore nel contenitore del livello superiore anziché creare un elenco di link agli elementi. Non abbiamo implementato questa soluzione a causa del modo in cui il recupero degli elementi secondari dell'elemento funziona in DevTools. Ogni elemento ha un puntatore principale utilizzato per recuperare gli elementi secondari ed è impossibile avere più puntatori. Pertanto, non possiamo avere un nodo che si espanda correttamente e contenga tutti i nodi secondari in più punti dell'albero. In generale, il sistema non è stato progettato tenendo conto dei sottoalberi duplicati.

Il compromesso a cui siamo giunti è stato creare link ai nodi DOM frontend anziché duplicarli. La classe responsabile della creazione di link agli elementi in DevTools è ShortcutTreeElement, che estende UI.TreeOutline.TreeElement. ShortcutTreeElement ha lo stesso comportamento degli altri elementi dell'albero DOM di DevTools, ma non ha un nodo corrispondente nel backend e ha un pulsante che rimanda a un ElementsTreeElement. Ogni ShortcutTreeElement al nodo del livello superiore ha un ShortcutTreeElement secondario che rimanda alla rappresentazione di uno pseudo-elemento ::backdrop nella struttura DOM di DevTools.

Progettazione iniziale:

Design iniziale.

Modifiche al protocollo Chrome DevTools (CDP)

Per implementare il supporto del livello superiore, sono necessarie modifiche al protocollo Chrome DevTools (CDP). CDP funge da protocollo di comunicazione tra DevTools e Chromium.

Dobbiamo aggiungere quanto segue:

  • Un comando da chiamare dal frontend in qualsiasi momento.
  • Un evento da attivare sul frontend dal lato del backend.

CDP: comando DOM.getTopLayerElements

Per visualizzare gli elementi attuali del livello superiore, abbiamo bisogno di un nuovo comando CDP sperimentale che restituisca un elenco di ID nodi degli elementi nel livello superiore. DevTools chiama questo comando ogni volta che vengono aperti o quando gli elementi del livello superiore cambiano. Il comando è il seguente:

  # 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: evento DOM.topLayerElementsUpdated

Per ottenere l'elenco aggiornato degli elementi del livello superiore, è necessario che ogni modifica degli elementi del livello superiore attivi un evento CDP sperimentale. Questo evento informa il frontend della modifica che poi chiama il comando DOM.getTopLayerElements e riceve l'elenco dei nuovi elementi.

L'evento sarà simile al seguente:

  # Called by the change of the top layer elements.
  experimental event topLayerElementsUpdated

Considerazioni relative al CDP

Esistono diverse opzioni per l'implementazione del supporto CDP del livello superiore. Un'altra opzione che abbiamo preso in considerazione è stata creare un evento che restituisse l'elenco degli elementi del livello superiore anziché semplicemente informare il front-end di un'aggiunta o rimozione di un elemento del livello superiore.

In alternativa, possiamo creare due eventi anziché il comando: topLayerElementAdded e topLayerElementRemoved. In questo caso, riceveremo un elemento e dovremo gestire l'array degli elementi del livello superiore sul front-end.

Attualmente, un evento frontend chiama il comando getTopLayerElements per ottenere un elenco di elementi aggiornati. Se inviassi un elenco di elementi o un elemento specifico che ha causato la modifica ogni volta che viene attivato un evento, potremmo evitare un passaggio di chiamata del comando. Tuttavia, in questo caso, il frontend perderebbe il controllo sugli elementi da inviare.

Lo abbiamo implementato in questo modo perché, a nostro avviso, è meglio che sia il frontend a decidere quando richiedere i nodi di primo livello. Ad esempio, se il livello superiore è compresso nell'interfaccia utente o se l'utente utilizza un riquadro di DevTools che non ha l'albero degli elementi, non è necessario recuperare i nodi aggiuntivi che potrebbero trovarsi più in profondità nell'albero.