Compatibilité des principales couches dans les outils pour les développeurs Chrome

Chrome DevTools prend désormais en charge les éléments de couche supérieure, ce qui permet aux développeurs de déboguer plus facilement leur code qui utilise ces éléments.

Cet article décrit les éléments de couche supérieure, comment les outils de développement permettent de visualiser le contenu de la couche supérieure pour comprendre et déboguer la structure DOM qui contient des éléments de couche supérieure, et comment la prise en charge de la couche supérieure par les outils de développement est implémentée.

Quels sont la couche supérieure et les éléments de la couche supérieure ?

Que se passe-t-il exactement en interne lorsque vous ouvrez un <dialog> en tant que modal ? 🤔

Il est placé dans une couche supérieure. Le contenu de la couche supérieure s'affiche au-dessus de tous les autres contenus. Par exemple, une boîte de dialogue modale doit s'afficher au-dessus de tous les autres contenus DOM. Le navigateur affiche donc automatiquement cet élément dans une "couche supérieure" au lieu de forcer les auteurs à gérer manuellement l'indice z. Un élément de la couche supérieure apparaît au-dessus d'un élément, même si celui-ci a le z-index le plus élevé.

La couche supérieure peut être décrite comme la "couche d'empilement la plus élevée". Chaque document ne possède qu'un seul viewport associé et, par conséquent, une seule couche supérieure. Plusieurs éléments peuvent se trouver dans la couche supérieure en même temps. Dans ce cas, elles s'empilent les unes sur les autres, la dernière étant en haut. En d'autres termes, tous les éléments de la couche supérieure sont placés dans une pile LIFO (last in, first out) dans la couche supérieure.

L'élément <dialog> n'est pas le seul élément que le navigateur affiche dans une couche supérieure. Actuellement, les éléments de la couche supérieure sont les popovers, les boîtes de dialogue modales et les éléments en mode plein écran.

Examinez l'implémentation de la boîte de dialogue suivante:

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

Voici une démonstration avec quelques boîtes de dialogue auxquelles des styles sont appliqués (décrits ci-dessous):

Qu'est-ce qu'un fond ?

Heureusement, il existe un moyen de personnaliser le contenu sous l'élément de la couche supérieure.

Chaque élément de la couche supérieure est associé à un pseudo-élément CSS appelé backdrop.

Le fond est un cadre de la taille de la fenêtre d'affichage qui est affiché immédiatement sous n'importe quel élément de la couche supérieure. Le pseudo-élément ::backdrop permet d'obscurcir, de styliser ou de masquer complètement tout ce qui se trouve en dessous de l'élément lorsqu'il s'agit de l'élément le plus élevé de la couche supérieure.

Lorsque vous rendez plusieurs éléments modaux, le navigateur dessine le fond immédiatement sous l'élément le plus en avant et au-dessus des autres éléments en plein écran.

Voici comment styliser un arrière-plan:

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

Comment afficher uniquement le premier arrière-plan ?

Chaque élément de la couche supérieure possède un arrière-plan appartenant à une pile de couches supérieures. Ces arrière-plans sont conçus pour se chevaucher. Par conséquent, si l'opacité d'un arrière-plan n'est pas de 100%, les arrière-plans situés en dessous sont visibles.

Si seul le premier arrière-plan de la pile de la couche supérieure doit être visible, vous pouvez y parvenir en gardant une trace des identifiants des éléments dans la pile de la couche supérieure.

Si l'élément ajouté n'est pas le premier de la couche supérieure, la fonction appelée lorsque l'élément est placé dans la couche supérieure applique une classe hiddenBackdrop à l'::backdrop. Cette classe est supprimée lorsque l'élément est supprimé de la couche supérieure.

Consultez le code de cet exemple de démonstration:

Conception de la compatibilité de la couche supérieure dans DevTools

La prise en charge de la couche supérieure par les outils de développement aide les développeurs à comprendre le concept de la couche supérieure et à visualiser comment son contenu change. Ces fonctionnalités aident les développeurs à identifier les éléments suivants:

  • Les éléments de la couche supérieure à tout moment et leur ordre.
  • Élément situé en haut de la pile à un moment donné.

De plus, la prise en charge de la couche supérieure dans les outils de développement permet de visualiser la position du pseudo-élément "backdrop" dans la pile de la couche supérieure. Même s'il ne s'agit pas d'un élément d'arborescence, il joue un rôle important dans le fonctionnement de la couche supérieure et peut être utile aux développeurs.

Les fonctionnalités d'assistance de la couche supérieure vous permettent d'effectuer les actions suivantes:

  1. Observez les éléments qui se trouvent dans la pile de la couche supérieure à tout moment. La pile de représentation de la couche supérieure change de manière dynamique à mesure que des éléments sont ajoutés ou supprimés de la couche supérieure.
  2. Afficher la position de l'élément dans la pile de la couche supérieure
  3. Passez de l'élément de la couche supérieure ou du pseudo-élément de fond des éléments dans l'arborescence à l'élément ou au pseudo-élément de fond dans le conteneur de représentation de la couche supérieure, puis inversement.

Voyons comment utiliser ces fonctionnalités.

Conteneur de la couche supérieure

Pour faciliter la visualisation des éléments de la couche supérieure, DevTools ajoute un conteneur de couche supérieure à l'arborescence des éléments. Il se trouve après la balise </html> fermante.

Ce conteneur vous permet d'observer les éléments de la pile de la couche supérieure à tout moment. Le conteneur de la couche supérieure est une liste de liens vers les éléments de la couche supérieure et leurs arrière-plans. La pile de représentation de la couche supérieure change de manière dynamique à mesure que des éléments sont ajoutés ou supprimés de la couche supérieure.

Pour trouver des éléments de la couche supérieure dans l'arborescence des éléments ou le conteneur de la couche supérieure, cliquez sur les liens entre la représentation de l'élément de la couche supérieure dans le conteneur de la couche supérieure et le même élément dans l'arborescence des éléments, puis inversement.

Pour passer de l'élément de conteneur de la couche supérieure à l'élément de l'arborescence de la couche supérieure, cliquez sur le bouton Afficher à côté de l'élément dans le conteneur de la couche supérieure.

Passer du lien du conteneur de la couche supérieure à l&#39;élément.

Pour passer de l'élément de l'arborescence de la couche supérieure au lien dans le conteneur de la couche supérieure, cliquez sur le badge couche supérieure à côté de l'élément.

Passer d&#39;un élément au lien du conteneur de la couche supérieure.

Vous pouvez désactiver n'importe quel badge, y compris celui de la couche supérieure. Pour désactiver les badges, effectuez un clic droit sur un badge, sélectionnez Paramètres des badges, puis décochez les cases à côté des badges que vous souhaitez masquer.

Désactivation du badge

Ordre des éléments dans la pile de la couche supérieure

Le conteneur de la couche supérieure affiche les éléments tels qu'ils apparaissent dans la pile, mais dans l'ordre inverse. L'élément supérieur de la pile est le dernier de la liste des éléments du conteneur de la couche supérieure. Cela signifie que le dernier élément de la liste du conteneur de la couche supérieure est celui avec lequel vous pouvez actuellement interagir dans le document.

Les badges à côté des éléments de l'arborescence indiquent si les éléments appartiennent à la couche supérieure et contiennent le numéro de position d'un élément dans la pile.

Dans cette capture d'écran, la pile de la couche supérieure se compose de deux éléments, le second étant en haut de la pile. Si vous supprimez le deuxième élément, le premier est déplacé vers le haut.

Ordre des éléments dans la pile.

Arrière-plans dans le conteneur de la couche supérieure

Comme indiqué ci-dessus, chaque élément de la couche supérieure possède un pseudo-élément CSS appelé "backdrop". Vous pouvez styliser cet élément. Il est donc utile de l'inspecter et de voir sa représentation.

Dans l'arborescence des éléments, un élément "backdrop" se trouve avant la balise de fermeture de l'élément auquel il appartient. Toutefois, dans le conteneur de la couche supérieure, un lien de toile de fond est listé juste au-dessus de l'élément de la couche supérieure auquel il appartient.

Position de la pile des arrière-plans.

Modifications apportées à l'arborescence DOM

ElementsTreeElement, la classe chargée de créer et de gérer des éléments d'arborescence DOM individuels dans DevTools, n'était pas suffisante pour implémenter un conteneur de couche supérieure.

Pour afficher le conteneur de la couche supérieure en tant que nœud dans l'arborescence, nous avons ajouté une classe qui crée des nœuds d'éléments d'arborescence DevTools. Auparavant, la classe chargée de créer l'arborescence des éléments DevTools initialisait chaque TreeElement avec un DOMNode, qui est une classe avec un backendNodeId et d'autres propriétés liées au backend. backendNodeId est ensuite attribué dans le backend.

Le nœud de conteneur de la couche supérieure, qui contient une liste de liens vers les éléments de la couche supérieure, devait se comporter comme un nœud d'élément d'arborescence standard. Toutefois, ce nœud n'est pas un nœud DOM "réel", et le backend n'a pas besoin de créer le nœud de conteneur de la couche supérieure.

Pour créer un nœud de frontend représentant la couche supérieure, nous avons ajouté un nouveau type de nœud de frontend créé sans DOMNode. Cet élément de conteneur de la couche supérieure est le premier nœud de frontend qui ne comporte pas de DOMNode. Il n'existe donc que sur le frontend et le backend ne le connaît pas. Pour obtenir le même comportement que les autres nœuds, nous avons créé une classe TopLayerContainer qui étend la classe UI.TreeOutline.TreeElement, qui est responsable du comportement des nœuds de frontend.

Pour obtenir l'emplacement souhaité, la classe qui affiche un élément associe TopLayerContainer en tant que frère suivant de la balise <html>.

Un nouveau badge de couche supérieure indique que l'élément se trouve dans la couche supérieure et sert de lien vers le raccourci de cet élément dans l'élément TopLayerContainer.

Conception initiale

Au départ, le plan consistait à dupliquer les éléments de la couche supérieure dans le conteneur de la couche supérieure au lieu de créer une liste de liens vers les éléments. Nous n'avons pas implémenté cette solution en raison de la façon dont la récupération des enfants de l'élément fonctionne dans DevTools. Chaque élément possède un pointeur parent utilisé pour extraire les enfants, et il est impossible d'avoir plusieurs pointeurs. Par conséquent, nous ne pouvons pas avoir un nœud qui se développe correctement et contient tous les enfants à plusieurs endroits de l'arborescence. En général, le système n'a pas été conçu pour les sous-arbres en double.

Nous avons donc décidé de créer des liens vers les nœuds DOM du frontend au lieu de les dupliquer. La classe chargée de créer des liens vers des éléments dans DevTools est ShortcutTreeElement, qui étend UI.TreeOutline.TreeElement. ShortcutTreeElement a le même comportement que les autres éléments de l'arborescence DOM DevTools, mais ne dispose pas de nœud correspondant côté backend et comporte un bouton qui renvoie à un ElementsTreeElement. Chaque ShortcutTreeElement du nœud de la couche supérieure possède un ShortcutTreeElement enfant qui renvoie à la représentation d'un pseudo-élément ::backdrop dans l'arborescence DOM de DevTools.

Conception initiale:

Conception initiale.

Modifications apportées au protocole Chrome DevTools (CDP)

Pour implémenter la prise en charge de la couche supérieure, des modifications du protocole CDP (Chrome DevTools Protocol) sont nécessaires. CDP sert de protocole de communication entre DevTools et Chromium.

Nous devons ajouter les éléments suivants:

  • Commande à appeler à tout moment depuis le frontend.
  • Événement à déclencher côté frontend à partir du backend.

CDP: commande DOM.getTopLayerElements

Pour afficher les éléments de la couche supérieure actuelle, nous avons besoin d'une nouvelle commande CDP expérimentale qui renvoie une liste des ID de nœud des éléments de la couche supérieure. Les outils pour les développeurs appellent cette commande chaque fois qu'ils sont ouverts ou que les éléments de la couche supérieure changent. La commande se présente comme suit :

  # 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: événement DOM.topLayerElementsUpdated

Pour obtenir la liste à jour des éléments de la couche supérieure, nous devons déclencher un événement CDP expérimental à chaque modification des éléments de la couche supérieure. Cet événement informe le frontend du changement, qui appelle ensuite la commande DOM.getTopLayerElements et reçoit la nouvelle liste d'éléments.

L'événement ressemble à ceci :

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

Considérations concernant la CDP

Plusieurs options étaient disponibles pour implémenter la prise en charge du CDP de la couche supérieure. Nous avons également envisagé de créer un événement qui renverrait la liste des éléments de la couche supérieure au lieu de simplement informer le front-end de l'ajout ou de la suppression d'un élément de la couche supérieure.

Nous pourrions également créer deux événements au lieu de la commande: topLayerElementAdded et topLayerElementRemoved. Dans ce cas, nous recevons un élément et devons gérer le tableau des éléments de la couche supérieure dans l'interface utilisateur.

Actuellement, un événement de front-end appelle la commande getTopLayerElements pour obtenir la liste des éléments mis à jour. Si nous envoyions une liste d'éléments ou un élément spécifique à l'origine du changement chaque fois qu'un événement est déclenché, nous pourrions éviter d'appeler la commande. Toutefois, dans ce cas, le frontend perd le contrôle des éléments à pousser.

Nous l'avons implémenté de cette manière, car, à notre avis, il est préférable que le frontend décide quand demander des nœuds de couche supérieure. Par exemple, si la couche supérieure est réduite dans l'UI ou si l'utilisateur utilise un panneau DevTools qui ne comporte pas l'arborescence des éléments, il n'est pas nécessaire d'obtenir les nœuds supplémentaires qui pourraient se trouver plus loin dans l'arborescence.