Compatibilidad con las capas superiores en las Herramientas para desarrolladores de Chrome

Chrome DevTools agregará compatibilidad con elementos de capa superior, lo que facilitará a los desarrolladores depurar su código que usa elementos de capa superior.

En este artículo, se describen qué son los elementos de la capa superior, cómo DevTools ayuda a visualizar el contenido de la capa superior para comprender y depurar la estructura del DOM que contiene elementos de la capa superior, y cómo se implementa la compatibilidad con la capa superior de DevTools.

¿Cuáles son la capa superior y los elementos de la capa superior?

¿Qué sucede exactamente de forma interna cuando abres un <dialog> como un elemento modal? 🤔

Se coloca en una capa superior. El contenido de la capa superior se renderiza sobre todo el resto del contenido. Por ejemplo, un diálogo modal debe aparecer sobre todo el resto del contenido del DOM, de modo que el navegador renderice automáticamente este elemento en una "capa superior" en lugar de obligar a los autores a luchar manualmente con el índice z. Un elemento de la capa superior aparece encima de un elemento incluso con el índice z más alto.

La capa superior se puede describir como "la capa de apilamiento más alta". Cada documento tiene una sola ventana de visualización asociada y, por lo tanto, también una sola capa superior. Varios elementos pueden estar dentro de la capa superior al mismo tiempo. Cuando eso sucede, se apilan uno encima del otro, y el último queda en la parte superior. En otras palabras, todos los elementos de la capa superior se colocan en una pila último en entrar, primero en salir (LIFO) en la capa superior.

El elemento <dialog> no es el único que el navegador renderiza en una capa superior. Actualmente, los elementos de la capa superior son los siguientes: ventanas emergentes, diálogos modales y elementos en un modo de pantalla completa.

Examina la siguiente implementación de diálogo:

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

Esta es una demostración con un par de diálogos que tienen estilos aplicados a sus fondos (los fondos se describen a continuación):

¿Qué es un fondo?

Por suerte, hay una forma de personalizar el contenido debajo del elemento de la capa superior.

Cada elemento de la capa superior tiene un pseudelemento CSS llamado fondo.

El fondo es un cuadro del tamaño de la ventana de visualización que se renderiza inmediatamente debajo de cualquier elemento de la capa superior. El pseudoelemento ::backdrop permite ocultar, aplicar diseño o esconder por completo todo lo que se encuentra debajo del elemento cuando es el más alto en la capa superior.

Cuando haces que varios elementos sean modales, el navegador dibuja el fondo inmediatamente debajo del elemento más frontal y encima de otros elementos de pantalla completa.

A continuación, te mostramos cómo aplicar diseño a un fondo:

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

¿Cómo mostrar solo el primer fondo?

Cada elemento de la capa superior tiene un fondo que pertenece a una pila de capas superior. Estos fondos están diseñados para superponerse entre sí, de modo que, si la opacidad de un fondo no es del 100%, los fondos que se encuentran debajo son visibles.

Si solo se debe ver el primer fondo de la pila de la capa superior, puedes hacer un seguimiento de los identificadores de elementos en la pila de la capa superior.

Si el elemento agregado no es el primero en la capa superior, la función a la que se llama cuando el elemento se coloca en la capa superior aplica una clase hiddenBackdrop a ::backdrop. Esta clase se quita cuando se quita el elemento de la capa superior.

Consulta el código en esta demostración de ejemplo:

Diseño de compatibilidad con la capa superior en DevTools

La compatibilidad de DevTools con la capa superior ayuda a los desarrolladores a comprender el concepto de la capa superior y visualizar cómo cambia el contenido de la capa superior. Estas funciones ayudan a los desarrolladores a identificar lo siguiente:

  • Los elementos de la capa superior en cualquier momento y su orden
  • El elemento que se encuentra en la parte superior de la pila en cualquier momento.

Además, la compatibilidad con la capa superior de DevTools ayuda a visualizar la posición del seudoelemento de fondo en la pila de la capa superior. Aunque no es un elemento de árbol, desempeña un papel importante en el funcionamiento de la capa superior y puede ser útil para los desarrolladores.

Con las funciones de asistencia de la capa superior, puedes hacer lo siguiente:

  1. Observar qué elementos están en la pila de la capa superior en cualquier momento La pila de representación de la capa superior cambia de forma dinámica a medida que se agregan o quitan elementos de la capa superior.
  2. Consulta la posición del elemento en la pila de la capa superior.
  3. Salta del elemento de la capa superior o del pseudoelemento de fondo de los elementos en el árbol al elemento o al pseudoelemento de fondo en el contenedor de representación de la capa superior y viceversa.

Veamos cómo usar estas funciones.

Contenedor de la capa superior

Para ayudar a visualizar los elementos de la capa superior, DevTools agrega un contenedor de capa superior al árbol de elementos. Reside después de la etiqueta de cierre </html>.

Este contenedor te permite observar los elementos de la pila de la capa superior en cualquier momento. El contenedor de la capa superior es una lista de vínculos a los elementos de la capa superior y sus fondos. La pila de representación de la capa superior cambia de forma dinámica a medida que se agregan o quitan elementos de la capa superior.

Para encontrar elementos de la capa superior dentro del árbol de elementos o el contenedor de la capa superior, haz clic en los vínculos de la representación del elemento de la capa superior en el contenedor de la capa superior al mismo elemento en el árbol de elementos y viceversa.

Para saltar del elemento del contenedor de la capa superior al elemento del árbol de la capa superior, haz clic en el botón mostrar junto al elemento en el contenedor de la capa superior.

Saltar del vínculo del contenedor de la capa superior al elemento

Para saltar del elemento del árbol de la capa superior al vínculo en el contenedor de la capa superior, haz clic en la insignia de capa superior junto al elemento.

Saltar de un elemento al vínculo del contenedor de la capa superior

Puedes desactivar cualquier insignia, incluida la de capa superior. Para inhabilitar las insignias, haz clic con el botón derecho en una, elige Configuración de insignias y borra las marcas junto a las insignias que quieras ocultar.

Desactivar la insignia.

Orden de los elementos en la pila de la capa superior

El contenedor de la capa superior muestra los elementos tal como aparecen en la pila, pero en orden inverso. La parte superior del elemento de pila es el último en la lista de elementos del contenedor de la capa superior. Esto significa que el último elemento de la lista de contenedores de la capa superior es el elemento con el que puedes interactuar actualmente en el documento.

Las insignias junto a los elementos del árbol indican si pertenecen a la capa superior y contienen el número de posición de un elemento en la pila.

En esta captura de pantalla, la pila de capas superior consta de dos elementos, con el segundo elemento en la parte superior de la pila. Si quitas el segundo elemento, el primero se moverá a la parte superior.

Es el orden de los elementos en la pila.

Fondos en el contenedor de la capa superior

Como se mencionó anteriormente, cada elemento de la capa superior tiene un pseudoelemento CSS llamado fondo. Puedes aplicarle diseño a este elemento, por lo que es útil inspeccionarlo y ver su representación.

En el árbol de elementos, un elemento de fondo reside antes de la etiqueta de cierre del elemento al que pertenece. Sin embargo, en el contenedor de la capa superior, hay un vínculo de fondo justo encima del elemento de la capa superior al que pertenece.

Posición de la pila de fondos.

Cambios en el árbol del DOM

ElementsTreeElement, la clase responsable de crear y administrar elementos individuales del árbol del DOM en DevTools, no era suficiente para implementar un contenedor de capa superior.

Para mostrar el contenedor de la capa superior como un nodo en el árbol, agregamos una clase nueva que crea nodos de elementos de árbol de DevTools. Anteriormente, la clase responsable de crear el árbol de elementos de DevTools inicializaba cada TreeElement con un DOMNode, que es una clase con un backendNodeId y otras propiedades relacionadas con el backend. backendNodeId, a su vez, se asigna en el backend.

El nodo contenedor de la capa superior, que tiene una lista de vínculos a elementos de la capa superior, debe comportarse como un nodo de elemento de árbol normal. Sin embargo, este nodo no es un nodo DOM "real" y el backend no necesita crear el nodo de contenedor de la capa superior.

Para crear un nodo de frontend que represente la capa superior, agregamos un nuevo tipo de nodo de frontend que se crea sin un DOMNode. Este elemento de contenedor de la capa superior es el primer nodo del frontend que no tiene un DOMNode, lo que significa que solo existe en el frontend y que el backend no lo "conoce". Para tener el mismo comportamiento que otros nodos, creamos una nueva clase TopLayerContainer que extiende la clase UI.TreeOutline.TreeElement, que es responsable del comportamiento de los nodos del frontend.

Para lograr la posición deseada, la clase que renderiza un elemento adjunta TopLayerContainer como el siguiente elemento hermano de la etiqueta <html>.

Una nueva insignia de capa superior indica que el elemento está en la capa superior y funciona como un vínculo al atajo de este elemento en el elemento TopLayerContainer.

Diseño inicial

Al principio, el plan era duplicar los elementos de la capa superior en el contenedor de la capa superior en lugar de crear una lista de vínculos a los elementos. No implementamos esta solución debido a la forma en que funciona la recuperación de los elementos secundarios en DevTools. Cada elemento tiene un puntero superior que se usa para recuperar elementos secundarios, y es imposible tener varios punteros. Por lo tanto, no podemos tener un nodo que se expanda correctamente y contenga todos los elementos secundarios en varios lugares del árbol. En general, el sistema no se compiló teniendo en cuenta los subárboles duplicados.

La solución a la que llegamos fue crear vínculos a los nodos DOM del frontend en lugar de duplicarlos. La clase responsable de crear vínculos a elementos en DevTools es ShortcutTreeElement, que extiende UI.TreeOutline.TreeElement. ShortcutTreeElement tiene el mismo comportamiento que otros elementos del árbol DOM de DevTools, pero no tiene un nodo correspondiente en el backend y tiene un botón que vincula a un ElementsTreeElement. Cada ShortcutTreeElement del nodo de la capa superior tiene un ShortcutTreeElement secundario que vincula a la representación de un pseudoelemento ::backdrop en el árbol del DOM de DevTools.

Diseño inicial:

Diseño inicial.

Cambios en el Protocolo de herramientas para desarrolladores de Chrome (CDP)

Para implementar la compatibilidad con la capa superior, se requieren cambios en el Protocolo de Herramientas para desarrolladores de Chrome (CDP). CDP funciona como un protocolo de comunicación entre DevTools y Chromium.

Necesitamos agregar lo siguiente:

  • Es un comando para llamar desde el frontend en cualquier momento.
  • Es un evento que se activa en el frontend desde el backend.

CDP: Comando DOM.getTopLayerElements

Para mostrar los elementos actuales de la capa superior, necesitamos un nuevo comando experimental de CDP que devuelva una lista de IDs de nodos de los elementos que se encuentran en la capa superior. DevTools llama a este comando cada vez que se abre DevTools o cuando cambian los elementos de la capa superior. El comando se ve de la siguiente manera:

  # 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

Para obtener la lista actualizada de los elementos de la capa superior, necesitamos que cada cambio de los elementos de la capa superior active un evento experimental de CDP. Este evento informa al frontend sobre el cambio que, luego, llama al comando DOM.getTopLayerElements y recibe la lista de elementos nuevos.

El evento tiene el siguiente aspecto:

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

Consideraciones de CDP

Había varias opciones para implementar la compatibilidad con CDP de la capa superior. Otra opción que consideramos fue crear un evento que devolviera la lista de los elementos de la capa superior en lugar de solo informar al frontend sobre la adición o eliminación de un elemento de la capa superior.

Como alternativa, podríamos crear dos eventos en lugar del comando: topLayerElementAdded y topLayerElementRemoved. En este caso, recibiríamos un elemento y tendríamos que administrar el array de los elementos de la capa superior en el frontend.

Actualmente, un evento del frontend llama al comando getTopLayerElements para obtener una lista de elementos actualizados. Si enviáramos una lista de elementos o un elemento específico que causó el cambio cada vez que se activa un evento, podríamos evitar un paso de la llamada al comando. Sin embargo, en este caso, el frontend perdería el control sobre qué elementos se envían.

Lo implementamos de esta manera porque, en nuestra opinión, es mejor que el frontend decida cuándo solicitar nodos de la capa superior. Por ejemplo, si la capa superior está contraída en la IU o el usuario usa un panel de DevTools que no tiene el árbol de elementos, no es necesario obtener los nodos adicionales que podrían estar más abajo en el árbol.