Ces dernières années, vous avez peut-être entendu parler de termes comme “Shadow DOM” et “Virtual DOM”. Bien qu’ils soient évidemment liés au DOM d’origine, ils se réfèrent à des concepts très différents. Dans cet article, je traiterai de ce qu’est, exactement, le Shadow DOM et en quoi il diffère du DOM original. Dans un prochain article, je ferai de même pour le DOM virtuel.

Il y a quelques semaines, j’ai écrit un article sur ce qu’est exactement le DOM. Pour résumer, le Document Object Model est une représentation d’un document HTML. Il est utilisé par les navigateurs pour déterminer ce qu’il faut rendre sur la page, et par les programmes Javascript pour modifier le contenu, la structure ou le style de la page.

Prenons par exemple le document HTML suivant :

<!doctype html>
<html lang="en">
 <head>
   <title>My first web page</title>
  </head>
 <body>
    <h1>Hello, world!</h1>
    <p>How are you?</p>
  </body>
</html>

Le document HTML ci-dessus donnera l’arborescence DOM suivante.

Qu'est ce que le Shadow DOM ?

Tout est global !

Tous les éléments et styles d’un document HTML, et par conséquent le DOM, sont dans un grand cadre global. Tout élément de la page est accessible par la méthode document.querySelector(), quelle que soit sa profondeur d’imbrication dans le document ou son emplacement. De même, le CSS appliqué au document peut sélectionner n’importe quel élément, peu importe où il se trouve.

Ce comportement peut être très utile lorsque l’on veut appliquer des styles à l’ensemble du document. Il est incroyablement utile de pouvoir sélectionner chaque élément d’une page et de définir, par exemple, son format de boîte, le tout sur une seule ligne.

* { box-sizing: border-box }

D’un autre côté, il y a des moments où un élément nécessite une encapsulation complète et nous ne voulons pas qu’il soit affecté par des styles même globaux. Les widgets tiers, tels que le bouton “follow” pour Twitter, en sont un bon exemple. Voici un exemple de ce à quoi ressemble ce widget :

En supposant que vous avez activé Javascript et que vous inspectez l’élément, vous remarquerez que le bouton twitter est un élément [iframe], qui charge un petit document avec le bouton stylé que vous voyez réellement.

C’est la seule façon pour Twitter de s’assurer que le style prévu de son widget ne sera pas affecté par une CSS dans le document incluant son widget. Bien qu’il existe des moyens d’utiliser la cascade pour essayer d’obtenir le même résultat, aucune autre méthode ne donnera la même garantie qu’un [iframe] le ferait, et ce n’est pas idéal.

Shadow DOM a été créé pour permettre nativement l’encapsulation et la mise en composant sur une page web sans avoir à s’appuyer sur des outils comme [iframe]s, qui n’ont pas vraiment été conçus à cette fin.

Un DOM dans un DOM

Vous pouvez considérer le Shadow DOM comme un “DOM dans un DOM”. C’est son propre arbre DOM isolé avec ses propres éléments et styles, complètement isolé du DOM original.

Bien qu’il n’ait été spécifié que récemment pour être utilisé par les auteurs Web, le DOM shadow est utilisé par les user agents depuis des années pour créer et styliser des composants complexes tels que des éléments de formulaire. Prenons l’élément [range] par exemple. Pour en créer un sur la page, il suffit d’ajouter l’élément suivant :

<input type="range">

Cet élément se traduit par l’élément suivant :

Si nous creusons plus profondément, nous verrons que cet élément est en fait composé de plusieurs éléments plus petits, contrôlant la piste et le curseur lui-même.

Qu'est ce que le Shadow DOM ?
Element “range” du shadow dom

Ceci est réalisé à l’aide du Shadow DOM. L’élément qui est exposé au document HTML de l’hôte est le simple input, mais en dessous il y a des éléments et des styles liés au composant qui ne font pas partie de la portée globale du DOM.

Comment fonctionne le Shadow DOM

Pour illustrer le fonctionnement du Shadow DOM, recréons le bouton “follow” de Twitter en utilisant le Shadow DOM au lieu d’un [iframe].

Tout d’abord, nous commençons par l’hôte fantôme (shadow host). C’est l’élément HTML habituel du DOM d’origine que nous voulons attacher au nouveau DOM shadow. Pour un composant comme le bouton Follow, il peut aussi contenir l’élément de repli que nous voulons afficher si Javascript n’est pas activé sur la page ou si le Shadow DOM n’est pas supporté.

<span class="shadow-host">
  <a href="https://twitter.com/twitter">
     Follow @twitter
  </a>
</span>

Notez que nous n’avons pas seulement utilisé l’élément [a] comme shadow hôte, car certains éléments, principalement des éléments interactifs, ne peuvent pas être des shadow hôtes.

Pour attacher un DOM d’ombre à notre hôte, nous utilisons la méthode attachShadow().

const shadowEl = document.querySelector(".shadow-host");
const shadow = shadowEl.attachShadow({mode: 'open'});

Ceci créera un shadow root vide en tant qu’enfant de notre shadow hôte. Le shadow root est le début d’un nouveau Shadow DOM de la même manière que l’élément [html] est le début du DOM original. Nous pouvons voir notre shadow root dans l’inspecteur devtools par #shadow-root.

Bien que les enfants HTML ordinaires soient visibles dans l’inspecteur, ils ne sont plus visibles sur la page lorsque le shadow root prend le dessus.

Ensuite, nous voulons créer le contenu pour former notre nouvel shadow tree. Le shadow arbre est comme un arbre DOM, mais pour un Shadow DOM au lieu d’un DOM normal. Pour créer notre bouton de suivi, tout ce dont nous avons besoin est un nouveau element [a], qui sera presque exactement le même que le lien de fallback que nous avons déjà, mais avec une icône.

const link = document.createElement("a");
link.href = shadowEl.querySelector("a").href;
link.innerHTML = `
    <span aria-label="Twitter icon"></span> 
    ${shadowEl.querySelector("a").textContent}
`;

Nous ajoutons ce nouvel élément à notre DOM shadow de la même manière que nous ajoutons un élément enfant à un autre, avec la méthode appendChild().

shadow.appendChild(link);

Enfin, nous pouvons ajouter des styles en créant un élément [style] et en l’ajoutant au shadow root.

const styles = document.createElement("style");
styles.textContent = `
a, span {
  vertical-align: top;
  display: inline-block;
  box-sizing: border-box;
}

a {
    height: 20px;
    padding: 1px 8px 1px 6px;
    background-color: #1b95e0;
    color: #fff;
    border-radius: 3px;
    font-weight: 500;
    font-size: 11px;
    font-family:'Helvetica Neue', Arial, sans-serif;
    line-height: 18px;
    text-decoration: none;   
}

a:hover {  background-color: #0c7abf; }

span {
    position: relative;
    top: 2px;
    width: 14px;
    height: 14px;
    margin-right: 3px;
    background: transparent 0 0 no-repeat;
    background-image: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2072%2072%22%3E%3Cpath%20fill%3D%22none%22%20d%3D%22M0%200h72v72H0z%22%2F%3E%3Cpath%20class%3D%22icon%22%20fill%3D%22%23fff%22%20d%3D%22M68.812%2015.14c-2.348%201.04-4.87%201.744-7.52%202.06%202.704-1.62%204.78-4.186%205.757-7.243-2.53%201.5-5.33%202.592-8.314%203.176C56.35%2010.59%2052.948%209%2049.182%209c-7.23%200-13.092%205.86-13.092%2013.093%200%201.026.118%202.02.338%202.98C25.543%2024.527%2015.9%2019.318%209.44%2011.396c-1.125%201.936-1.77%204.184-1.77%206.58%200%204.543%202.312%208.552%205.824%2010.9-2.146-.07-4.165-.658-5.93-1.64-.002.056-.002.11-.002.163%200%206.345%204.513%2011.638%2010.504%2012.84-1.1.298-2.256.457-3.45.457-.845%200-1.666-.078-2.464-.23%201.667%205.2%206.5%208.985%2012.23%209.09-4.482%203.51-10.13%205.605-16.26%205.605-1.055%200-2.096-.06-3.122-.184%205.794%203.717%2012.676%205.882%2020.067%205.882%2024.083%200%2037.25-19.95%2037.25-37.25%200-.565-.013-1.133-.038-1.693%202.558-1.847%204.778-4.15%206.532-6.774z%22%2F%3E%3C%2Fsvg%3E);
}
`;

shadow.appendChild(styles);

Voici notre élément final :

Qu'est ce que le Shadow DOM ?
Suivez @twitter

Le DOM vs le Shadow DOM

D’une certaine manière, le Shadow DOM est une version ” allégée” du DOM. Comme le DOM, c’est une représentation d’éléments HTML, utilisée pour déterminer ce qu’il faut rendre sur la page et permettre la modification des éléments. Mais contrairement au DOM, le Shadow DOM n’est pas basé sur un document complet et autonome. Un DOM shadow, comme son nom l’indique, est toujours attaché à un élément dans un DOM normal. Sans le DOM, un Shadow DOM n’existe pas.

Catégories : javascript

siddhy

Développeur web full stack depuis une 15aine d'année dans une agence web du sud de la France et Geek depuis toujours, l'apprentissage et le partage font parti intégrante de ma philosophie au même titre que l'évolution personnelle et la sagesse bouddhiste.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *