Supporto di livello superiore in Chrome DevTools

Alina Varkki
Alina Varkki

Chrome DevTools aggiunge il supporto per gli elementi del livello superiore, consentendo agli sviluppatori di eseguire più facilmente il debug del codice che utilizza gli elementi del livello principale.

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

Quali sono gli elementi del livello superiore e del livello superiore?

Cosa succede esattamente internamente quando apri una <dialog> come finestra modale? 🤔

Viene inserito in uno strato superiore. I contenuti del livello superiore vengono visualizzati sopra tutti gli altri contenuti. Ad esempio, una finestra di dialogo modale deve apparire sopra tutti gli altri contenuti DOM, quindi il browser esegue automaticamente il rendering di questo elemento in uno "livello superiore" invece di costringere gli autori a combattere manualmente lo z-index. Un elemento del livello superiore viene visualizzato sopra un elemento anche con lo z-index più alto.

Il livello superiore può essere descritto come "il livello di impilamento più alto". A ogni documento è associata una singola area visibile e, di conseguenza, anche un unico livello superiore. All'interno del livello superiore possono trovarsi contemporaneamente più elementi. In questi casi, vengono impilati l'uno sull'altro e l'ultimo viene sovrapposto. In altre parole, tutti gli elementi del livello superiore sono posizionati in uno stack LIFO (last in, first out) 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 delle finestre 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 in cui sono applicati stili agli sfondi (sfondi descritti di seguito):

Che cos'è uno sfondo?

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

Ogni elemento nel livello superiore ha uno pseudo-elemento CSS chiamato sfondo.

Lo sfondo è un riquadro delle dimensioni dell'area visibile che viene visualizzato immediatamente sotto ogni elemento del livello superiore. Lo pseudo-elemento ::backdrop consente di oscurare, applicare stili o nascondere completamente tutto ciò che si trova sotto l'elemento quando è quello più in alto nel livello superiore.

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

Ecco come applicare lo 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 mostrare solo il primo sfondo?

Ogni elemento del livello superiore ha uno sfondo che appartiene a uno stack di livelli superiore. Questi sfondi sono progettati per sovrapporsi l'uno all'altro, pertanto se l'opacità di uno sfondo non è pari al 100%, quelli sottostanti sono visibili.

Se deve essere visibile solo il primo sfondo nella pila di livelli superiore, puoi farlo tenendo traccia degli identificatori degli elementi nella pila di livelli superiore.

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

Guarda il codice in questa demo di esempio:

Supporto alla progettazione di livello superiore in DevTools

Il supporto DevTools per il livello superiore aiuta gli sviluppatori a comprendere il concetto del livello superiore e a visualizzare come cambiano i contenuti del livello superiore. Queste funzionalità consentono agli sviluppatori di identificare quanto segue:

  • Gli elementi nel livello superiore in qualsiasi momento e il loro ordine.
  • L'elemento in cima alla pila in qualsiasi momento.

Inoltre, il supporto del livello superiore di DevTools aiuta a visualizzare la posizione dello pseudo elemento di sfondo nel livello superiore. Anche se non è un elemento ad albero, svolge un ruolo importante nel funzionamento del livello superiore e può essere utile per gli sviluppatori.

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

  1. Osserva in qualsiasi momento quali elementi si trovano nello stack del livello superiore. Lo stack di rappresentazione del livello superiore cambia in modo dinamico man mano che gli elementi vengono aggiunti o rimossi dal livello superiore.
  2. Visualizza la posizione dell'elemento nel livello superiore.
  3. Passa dall'elemento del livello superiore o dallo pseudo-elemento di sfondo degli elementi nell'albero allo pseudo-elemento dell'elemento o dello sfondo nel contenitore di rappresentazione del livello superiore e viceversa.

Vediamo come usare queste funzionalità.

Contenitore livello superiore

Per visualizzare gli elementi del livello superiore, DevTools aggiunge un container del livello superiore all'albero degli elementi. Si trova dopo il tag di chiusura </html>.

Questo contenitore ti consente di osservare gli elementi nel livello superiore dello stack in qualsiasi momento. Il contenitore del livello superiore è un elenco di link agli elementi del livello superiore e ai relativi sfondi. Lo stack di rappresentazione del livello superiore cambia in modo dinamico man mano che gli elementi vengono aggiunti o rimossi dal livello superiore.

Per trovare elementi del livello superiore nell'albero degli elementi o nel contenitore del livello superiore, fai clic sui link dalla rappresentazione dell'elemento del livello superiore nel contenitore del livello superiore allo stesso elemento nella struttura ad albero e indietro.

Per passare dall'elemento contenitore di livello superiore all'elemento con albero di livello superiore, fai clic sul pulsante Scopri accanto all'elemento nel contenitore del livello superiore.

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

Per passare dall'elemento con 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 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 sui badge desiderati, scegli Impostazioni badge e deseleziona i segni di spunta accanto ai badge che vuoi nascondere.

Disattivazione del badge in corso.

Ordine degli elementi nello stack del livello superiore

Il contenitore del livello superiore mostra gli elementi come vengono visualizzati nella pila, ma in ordine inverso. La parte superiore dell'elemento stack è l'ultimo nell'elenco degli elementi del contenitore del livello superiore. Ciò significa che l'ultimo elemento nell'elenco dei contenitori del livello superiore è quello con cui puoi interagire attualmente 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 nell'elenco.

In questo screenshot, lo stack del livello superiore è costituito da due elementi e il secondo elemento si trova in cima. Se rimuovi il secondo elemento, il primo si sposta in alto.

L&#39;ordine degli elementi nello stack.

Sfondi nel contenitore del livello superiore

Come accennato in precedenza, ogni elemento del livello superiore ha uno pseudo-elemento CSS chiamato sfondo. Puoi assegnare uno stile a questo elemento, perciò è utile anche ispezionarlo e vederne la rappresentazione.

Nell'albero degli elementi, un elemento di sfondo risiede prima del tag di chiusura dell'elemento a cui appartiene. Tuttavia, nel contenitore del livello superiore, viene visualizzato un link di sfondo subito sopra l'elemento del livello superiore a cui appartiene.

Posizione pila degli sfondi.

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 container di livello superiore.

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

Il nodo container del livello superiore, che contiene un elenco di link agli elementi del livello superiore, deve comportarsi come un normale nodo di elementi ad albero. Tuttavia, questo nodo non è un nodo DOM "reale" e il backend non ha bisogno di creare il nodo container di livello superiore.

Per creare un nodo frontend che rappresenta il livello superiore, abbiamo aggiunto un nuovo tipo di nodo frontend creato senza DOMNode. Questo elemento container di livello superiore è il primo nodo frontend che non dispone di DOMNode, il che significa che esiste solo sul frontend e il backend non ne è a conoscenza. 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 gemello 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

All'inizio, il piano prevedeva di duplicare gli elementi del livello superiore nel contenitore del livello superiore invece di creare un elenco di link agli elementi. Non abbiamo implementato questa soluzione a causa del modo in cui funziona il recupero degli elementi figlio degli elementi in DevTools. Ogni elemento ha un puntatore padre utilizzato per il recupero dei figli ed è impossibile avere più puntatori. Di conseguenza, non possiamo avere un nodo che si espande correttamente e contenga tutti gli elementi secondari in più posizioni dell'albero. In generale, il sistema non è stato creato pensando a sottoalbero duplicati.

La compromissione a cui siamo arrivati è stata la creazione di collegamenti ai nodi DOM del frontend, invece di 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 che rimanda al nodo del livello superiore ha un elemento ShortcutTreeElement secondario che si collega alla rappresentazione di uno pseudo-elemento ::backdrop nella struttura DOM di DevTools.

Progettazione iniziale:

Progettazione iniziale.

Modifiche al protocollo CDP (Chrome DevTools)

Per implementare il supporto di livello superiore, sono necessarie modifiche al protocollo CDP (Chrome DevTools). 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 backend.

CDP: comando DOM.getTopLayerElements

Per visualizzare gli elementi del livello superiore correnti, è necessario un nuovo comando CDP sperimentale che restituisca un elenco degli ID nodo degli elementi che si trovano nel livello superiore. DevTools chiama questo comando ogni volta che vengono aperti gli strumenti DevTools o quando gli elementi del livello superiore cambiano. Il comando è simile al 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, è necessaria ogni modifica degli elementi del livello superiore per attivare un evento CDP sperimentale. Questo evento informa il frontend della modifica che poi chiama il comando DOM.getTopLayerElements e riceve il nuovo elenco degli elementi.

L'evento sarà simile al seguente:

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

Considerazioni su CDP

C'erano più opzioni su come implementare il supporto CDP per il livello superiore. Un'altra opzione che abbiamo preso in considerazione era la creazione di un evento che restituisse l'elenco degli elementi del livello superiore invece di informare semplicemente il front-end dell'aggiunta o della rimozione di un elemento del livello superiore.

In alternativa, potremmo creare due eventi al posto del comando: topLayerElementAdded e topLayerElementRemoved. In questo caso, riceveremmo un elemento e dovremo gestire l'array degli elementi del livello superiore nel front-end.

Attualmente, un evento di frontend chiama il comando getTopLayerElements per ottenere un elenco di elementi aggiornati. Se inviassimo un elenco di elementi o un elemento specifico che causa la modifica ogni volta che viene attivato un evento, potremmo evitare di chiamare il comando soltanto una volta. Tuttavia, in questo caso, il frontend perderebbe il controllo sugli elementi da inviare.

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