Comprendre la ViewEncapsulation dans un Component Angular

Simon Bernard
3 min readMar 8, 2017

--

Les composants Angular permettent d’encapsuler les différentes fonctionnalités de votre application dans une class, un template et une feuille de style. Cette encapsulation peut se matérialiser de 3 manières et Angular nous permet évidement de le contrôler. Pourquoi 3 types d’encapsulations me direz-vous ? C’est tout simplement pour pouvoir contrôler comment le Shadow DOM va être implémenté par Angular pour notre composant.

Mais qu’est-ce que le Shadow DOM

Le Shadow DOM fait parti des Web Components qui sont un ensemble de technologies permettant justement le développement d’interfaces ou de widgets réutilisables nativement dans le navigateur. En clair, il permet de définir du comportement interne à notre DOM sans qu’il interfère sur les autres parties de notre application. Il permet aussi de définir du style spécifique.

Pour, plus de détails sur les Web Components et le DOM Shadow en particulier.

Et pourquoi est-ce important en Angular ?

Lorsque l’on créé un component Angular, le framework va tout simplement utiliser cette logique de Web Components pour créer le nouvel élément HTML qui va porter la logique de notre component.

La logique de cette organisation est que chaque composant, s’il est bien fait, pourra être exporté dans n’importe quel contexte. Comportement très pratique pour ne pas avoir à re-développer des composants similaires d’une application à l’autre. Autre avantage, les Web Components étant natifs, l’environnement applicatif ne limite plus l’utilisation de vos components à toutes vos apps.

Les types d’encapsulations

Angular fournit trois possibilités d’encapsulations:

  • None: où comme on le devine, le Shadow DOM ne sera pas utilisé. Le CSS ne sera pas encapsulé non plus.
  • Emulated: le Shadow DOM ne sera pas utilisé non plus mais une encapsulation du CSS sera faite par Angular.
  • Native: Angular créera un Web Component complet avec l’utilisation du Shadow DOM et du CSS scopé au component.

Ces trois possibilités sont données pour laisser le choix au développeur selon leurs besoins mais également pour gérer la compatibilité des Web Components qui n’est évidemment pas complète.

Comment déclarer le type d’encapsulation ?

Lorsque l’on crée un Component, la définition du type est une option dans le décorateur @component() .

Dans le cas d’une ViewEncapsulation.None, aucune règle CSS ne sera scopée au component. Dans ce cas, il est possible que le CSS d’autres components écrase les règles définies dans celui-ci.

import {ViewEncapsulation} from '@angular/core';

@Component({
selector: 'my-random',
templateUrl: 'my-random.component.html',
encapsulation: ViewEncapsulation.None})
class MyRandomComponent {}

Lorsque la propriété ViewEncapsulation.Emulated est définie (se sera souvent le cas puisque c’est le type d’encapsulation par défaut), Angular sera capable de limiter le scope des propriétés CSS à ce component uniquement pour éviter tout débordement de style à d’autre partie de l’application. Et tout cela, sans utiliser le Shadow DOM pour autant.

import {ViewEncapsulation} from '@angular/core';

@Component({
selector: 'my-random',
templateUrl: 'my-random.component.html',
encapsulation: ViewEncapsulation.Emulated})
class MyRandomComponent {}

Dans cet exemple, Angular va prévoir la génération du template avec cette contrainte. Une fois le HTML compilé, on voit que des attributs se sont rajoutés sur l’élément de notre composant ainsi que sur tous les éléments fils.

<my-random _ngcontent-0 _nghost-1>
<div class="random" _ngcontent-1>
...

</div>
</my-random>

Le CSS généré va donc pouvoir être complètement isolé à notre composant.

<head>
<style>.random[_ngcontent-1] {
...
}</style>
</head>

Dans le cas de ViewEncapsulation.Native, Angular va être capable de définir un Web Component de manière complètement automatique. La syntaxe est donc très prévisible.

import {ViewEncapsulation} from '@angular/core';

@Component({
selector: 'my-random',
templateUrl: 'my-random.component.html',
encapsulation: ViewEncapsulation.Native})
class MyRandomComponent {}

Lors de la compilation, Angular va référencer notre component en tant que Web Component natif et le HTML généré va donc paraître un peu exotique si l’on n’est pas familier avec la norme (cf lien en début d’article).

<my-random>
#shadow-root
| <style>
| .random {
| ...
| }
| </style>
| <div class="random">
| ...
| </div>
</my-random>

Même si la syntaxe ne ressemble pas à notre HTML, on peut clairement voir que la balise de style générée appartient bien à notre Web Component matérialisé par l’élément #shadow-root. Le CSS ne pourra donc jamais déborder de son scope car le reste de la page n’a pas connaissance des règles définies dans ce component.

Merci à Pascal Precht ʕ•̫͡•ʔ pour son article qui m’a servi de base.

--

--

Simon Bernard

Senior developer & Architect Front End @SignkickUK. Focused on modern JS/TS, Angular & Node.