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

Alina Varkki
Alina Varkki

Las herramientas para desarrolladores de Chrome están agregando compatibilidad con los elementos de la capa superior, lo que facilita a los desarrolladores depurar el código que utiliza los elementos de la capa superior.

En este artículo, se describe qué son los elementos de la capa superior, cómo las Herramientas para desarrolladores ayudan a visualizar el contenido de esa capa para comprender y depurar la estructura del DOM que contiene elementos de esa capa, y cómo se implementa su compatibilidad.

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

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

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

La capa superior puede describirse como "la capa de apilado más alta". Cada documento tiene un solo viewport asociado y, por lo tanto, también una sola capa superior. En la capa superior, pueden haber varios elementos al mismo tiempo. Cuando eso sucede, se apilan una encima de la otra, y la última se coloca encima. En otras palabras, todos los elementos de las capas superiores se colocan en una pila del tipo ú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 modo de pantalla completa.

Examina la siguiente implementación de diálogos:

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

Aquí hay 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?

Afortunadamente, existe una manera de personalizar el contenido debajo del elemento de la capa superior.

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

El fondo es un cuadro del tamaño del viewport que se renderiza inmediatamente debajo de cualquier elemento de capa superior. El seudoelemento ::backdrop permite ocultar, aplicar ajustes de estilo o ocultar por completo todo lo que se ubica debajo del elemento cuando este es el que está más arriba en la capa superior.

Cuando haces modal varios elementos, el navegador dibuja el fondo inmediatamente debajo del elemento que se encuentra más frontal y sobre otros elementos de pantalla completa.

Para darle estilo a un fondo, sigue estos pasos:

/* 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 capa 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 están debajo serán visibles.

Si solo es necesario que el primer fondo de la pila de capas superior sea visible, puedes realizar un seguimiento de los identificadores de elementos en la pila de capas 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.

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

Diseño de compatibilidad de la capa superior en Herramientas para desarrolladores

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

  • Los elementos de la capa superior en cualquier momento y en su orden.
  • Elemento en la parte superior de la pila en cualquier momento.

Además, la compatibilidad con la capa superior de Herramientas para desarrolladores ayuda a visualizar la posición del seudoelemento de fondo en la pila de capas 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 compatibilidad de la capa superior, puedes hacer lo siguiente:

  1. Observa 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. Observa la posición del elemento en la pila de la capa superior.
  3. Saltar desde los elementos de la capa superior seudoelemento de fondo en el árbol hasta el elemento o seudoelemento de fondo en el contenedor de representación de la capa superior y el fondo.

Veamos cómo usar estas funciones.

Contenedor de la capa superior

Para visualizar los elementos de la capa superior, las Herramientas para desarrolladores agrega un contenedor de la capa superior al árbol de elementos. Se encuentra 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 enlaces 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 buscar elementos de la capa superior dentro del árbol de elementos o del 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 hasta el mismo elemento en el árbol de elementos y viceversa.

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

Salto del vínculo del contenedor de la capa superior al elemento.

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

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

Puedes desactivar cualquier insignia, incluida la de capa superior. Para inhabilitarlas, haz clic con el botón derecho en cualquiera de ellas, elige Configuración de insignias y desmarca las marcas que aparecen junto a las insignias que quieres ocultar.

Desactivando 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 la 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 estos 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 seudoelemento CSS llamado fondo. Puedes aplicar diseño a este elemento, por lo que también será ú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, aparece 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 Herramientas para desarrolladores, no fue suficiente para implementar un contenedor de la 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 Herramientas para desarrolladores. Anteriormente, la clase responsable de crear el árbol de elementos de Herramientas para desarrolladores inicializa cada TreeElement con un DOMNode, que es una clase con un backendNodeId y otras propiedades relacionadas con el backend. A su vez, backendNodeId se asigna en el backend.

El nodo del contenedor de la capa superior, que tiene una lista de vínculos a los elementos de la capa superior, debe comportarse como un nodo normal de elementos de árbol. Sin embargo, este nodo no es “real” No es necesario que el nodo del DOM y el backend creen el nodo del contenedor de la capa superior.

Para crear un nodo frontend que represente la capa superior, agregamos un nuevo tipo de nodo frontend que se crea sin un DOMNode. Este elemento de contenedor de la capa superior es el primer nodo de frontend que no tiene un DOMNode, lo que significa que existe solo en el frontend y el backend no se "conoce" al respecto. 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 de frontend.

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

Una nueva insignia de capa superior indica que el elemento está en la capa superior y sirve como vínculo a un acceso directo de este elemento en el elemento TopLayerContainer.

Diseño inicial

Al principio, el plan consistía en duplicar los elementos de la capa superior en el contenedor de la capa superior en lugar de crear una lista de enlaces a los elementos. No implementamos esta solución debido a la forma en que funciona la recuperación de los elementos secundarios en Herramientas para desarrolladores. 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 vulneración a la que llegamos fue crear vínculos a los nodos del DOM de frontend en lugar de duplicarlos. La clase responsable de crear vínculos a elementos en Herramientas para desarrolladores es ShortcutTreeElement, que extiende UI.TreeOutline.TreeElement. ShortcutTreeElement tiene el mismo comportamiento que otros elementos del árbol del DOM de Herramientas para desarrolladores, pero no tiene un nodo correspondiente en el backend y tiene un botón que se vincula a un ElementsTreeElement. Cada ShortcutTreeElement del nodo de la capa superior tiene un ShortcutTreeElement secundario que se vincula a la representación de un seudoelemento ::backdrop en el árbol del DOM de Herramientas para desarrolladores.

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 deben realizar cambios en el protocolo de Herramientas para desarrolladores de Chrome (CDP). CDP funciona como un protocolo de comunicación entre Herramientas para desarrolladores y Chromium.

Debemos agregar lo siguiente:

  • Un comando para llamar desde el frontend en cualquier momento.
  • Un evento que se activará en el frontend desde el backend.

CDP: comando DOM.getTopLayerElements

Para mostrar los elementos actuales de la capa superior, necesitamos un nuevo comando CDP experimental que muestra una lista de los ID de nodo de los elementos que se encuentran en la capa superior. Herramientas para desarrolladores llama a este comando cada vez que las Herramientas para desarrolladores se abren 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 de CDP experimental. Este evento informa al frontend del 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 múltiples opciones sobre cómo se podía implementar la compatibilidad de CDP de la capa superior. Otra opción que tuvimos en cuenta fue crear un evento que mostrara la lista de los elementos de la capa superior en lugar de simplemente 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 necesitaríamos administrar el array de los elementos de la capa superior en el frontend.

Actualmente, un evento de frontend llama al comando getTopLayerElements para obtener una lista de los elementos actualizados. Si enviáramos una lista de elementos o un elemento específico que ocasione el cambio cada vez que se activa un evento, podríamos evitar llamar al comando por un paso. Sin embargo, en este caso, el frontend perdería el control de los elementos que se envían.

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