Supporto di livello superiore in Chrome DevTools

Alina Varkki
Alina Varkki

Chrome DevTools sta aggiungendo il supporto per gli elementi di livello superiore, semplificando il debug del codice che utilizza gli elementi del livello superiore per gli sviluppatori.

Questo articolo descrive cosa sono gli elementi del livello superiore, in che modo DevTools consente di 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 superiore?

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

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

Il livello superiore può essere descritto come "il livello di sovrapposizione più elevato". A ogni documento è associata una singola area visibile e, di conseguenza, anche un singolo livello superiore. Possono essere presenti più elementi contemporaneamente all'interno del livello superiore. Quando ciò accade, si impilano uno sull'altro, ovvero l'ultimo sopra. In altre parole, tutti gli elementi del livello superiore vengono posizionati in una pila 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 con stili applicati agli sfondi (gli sfondi descritti di seguito):

Che cos'è uno sfondo?

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

Ogni elemento nel livello superiore ha uno pseudoelemento CSS chiamato sfondo.

Lo sfondo è una casella delle dimensioni dell'area visibile, che viene visualizzata subito sotto qualsiasi elemento del livello superiore. Lo pseudoelemento ::backdrop consente di oscurare, personalizzare 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 subito sotto l'elemento più in primo piano e sopra gli altri elementi a schermo intero.

Ecco come puoi modificare lo stile di 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 si fa a mostrare solo il primo sfondo?

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

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

Se l'elemento aggiunto non è il primo nel livello superiore, la funzione richiamata 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.

Controlla il codice di questa demo di esempio:

Progettazione di supporto di 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 come cambiano i contenuti del livello superiore. Queste funzionalità aiutano gli sviluppatori a 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 consente di visualizzare la posizione dello pseudoelemento di sfondo nell'elenco dei livelli superiori. Anche se non si tratta di 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. Puoi osservare in qualsiasi momento quali elementi sono presenti nello stack del livello superiore. Lo stack di rappresentazioni del livello superiore cambia in modo dinamico man mano che vengono aggiunti o rimossi elementi dal livello superiore.
  2. Visualizza la posizione dell'elemento nella pila del livello superiore.
  3. Passa dall'elemento o dagli elementi del livello superiore pseudo-elemento sfondo nell'albero all'elemento o pseudo-elemento sfondo nel contenitore di rappresentazione del livello superiore e viceversa.

Vediamo come utilizzare queste funzionalità.

Container del livello superiore

Per aiutarti a 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 in qualsiasi momento gli elementi nella pila di livelli superiore. Il contenitore del livello superiore è un elenco di link agli elementi del livello superiore e ai relativi sfondi. Lo stack di rappresentazioni del livello superiore cambia in modo dinamico man mano che vengono aggiunti o rimossi elementi dal livello superiore.

Per trovare gli elementi del livello superiore nell'albero 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 degli elementi e viceversa.

Per passare dall'elemento contenitore del livello superiore all'elemento ad 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 ad albero del livello superiore al link nel contenitore del livello superiore, fai clic sul badge del livello superiore accanto all'elemento.

Passaggio da un elemento al link contenitore del livello superiore.

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

Disattivazione del badge.

Ordine degli elementi nella pila del livello superiore

Il contenitore del livello superiore mostra gli elementi come appaiono nella pila, ma in ordine inverso. La parte superiore dell'elemento stack è l'ultimo nell'elenco di elementi del contenitore del livello superiore. Ciò significa che l'ultimo elemento nell'elenco dei contenitori del livello superiore è quello con cui puoi attualmente interagire 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, la pila del livello superiore è composta da due elementi, con il secondo in cima. Se rimuovi il secondo elemento, il primo si sposta nella parte superiore.

L&#39;ordine degli elementi nella pila.

Sfondi nel contenitore del livello superiore

Come accennato in precedenza, ogni elemento di livello superiore ha uno pseudoelemento CSS chiamato sfondo. Puoi applicare uno stile a questo elemento, quindi è utile anche ispezionarlo e vederne la rappresentazione.

Nell'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, sopra l'elemento del livello superiore a cui appartiene è riportato un link di sfondo.

Posizione dell&#39;elenco 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 nell'albero, abbiamo aggiunto una nuova classe che crea nodi di elementi ad albero di DevTools. In precedenza, la classe responsabile della creazione ad albero di elementi DevTools veniva inizializzata ogni TreeElement con un DOMNode, ovvero una classe con backendNodeId e altre proprietà relative al backend. backendNodeId, a sua volta, viene assegnato sul backend.

Il nodo contenitore del livello superiore, che ha un elenco di link agli elementi del livello superiore, doveva comportarsi come un normale nodo di elementi ad albero. Tuttavia, questo nodo non è "reale" Non è necessario che il nodo DOM e il backend creino il nodo container di livello superiore.

Per creare un nodo frontend che rappresenti 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 ha un DOMNode, il che significa che esiste solo sul frontend e il backend non sa su di esso. 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 collega TopLayerContainer come gemello successivo del tag <html>.

Un nuovo badge di 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 anziché creare un elenco di link agli elementi. Non abbiamo implementato questa soluzione a causa del modo in cui funziona il recupero dei valori secondari dell'elemento in DevTools. Ogni elemento ha un puntatore padre utilizzato per recuperare gli elementi secondari e non è possibile avere più puntatori. Pertanto, non possiamo avere un nodo che si espanda correttamente e contenga tutti gli elementi secondari in più punti dell'albero. In generale, il sistema non è stato realizzato tenendo conto di sottoalberi duplicati.

La compromissione a cui siamo arrivati è stata la creazione di collegamenti ai nodi DOM del frontend invece di duplicare i nodi. La classe responsabile della creazione di link agli elementi in DevTools è ShortcutTreeElement, che estende il UI.TreeOutline.TreeElement. ShortcutTreeElement ha lo stesso comportamento di altri elementi dell'albero DOM di DevTools ma non ha un nodo corrispondente nel backend e ha un pulsante che si collega a un ElementsTreeElement. Ogni ShortcutTreeElement al nodo del livello superiore ha un ShortcutTreeElement figlio che si collega alla rappresentazione di uno pseudo-elemento ::backdrop nell'albero DOM di DevTools.

Progettazione iniziale:

Progettazione iniziale.

Modifiche al protocollo CDP (Chrome DevTools)

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 backend.

CDP: comando DOM.getTopLayerElements

Per visualizzare gli elementi del livello superiore corrente, è necessario un nuovo comando CDP sperimentale che restituisca un elenco di ID nodo degli elementi presenti nel livello superiore. DevTools chiama questo comando ogni volta che i DevTools vengono aperti o quando cambiano gli elementi del livello superiore. Il comando ha questo aspetto:

  # 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, abbiamo bisogno di ogni modifica di questi elementi per attivare un evento CDP sperimentale. Questo evento informa il frontend della modifica che quindi chiama il comando DOM.getTopLayerElements e riceve il nuovo elenco di elementi.

L'evento ha il seguente aspetto:

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

Considerazioni su CDP

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

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

Al momento, un evento di frontend chiama il comando getTopLayerElements per ottenere un elenco degli elementi aggiornati. Se dovessimo inviare un elenco di elementi o un elemento specifico che ha causato la modifica ogni volta che viene attivato un evento, potremmo evitare un solo passaggio per chiamare il comando. Tuttavia, in questo caso, il frontend perderebbe il controllo sugli elementi inviati tramite push.

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 privo dell'albero degli elementi, non è necessario ottenere i nodi aggiuntivi che potrebbero trovarsi più in profondità nell'albero.