image auteur
Lucas BENTO-VERSACE 6min • 27-12-2022

Angular - View Encapsulation

Angular - View Encapsulation

Bienvenue sur CodeWise ! Si vous êtes nouveau ici, vous voudrez sans doute découvrir notre Starter Kit Angular : il contient une roadmap du parcours d'un dev Angular, ainsi qu'un cookbook des commandes les plus utiles et un extrait de formation. Cliquez ici pour le télécharger (c’est gratuit !)

Comprenez la view encapsulation dans Angular et comment l'utiliser.

Qu'est-ce que la view encapsulation ?

La view encapsulation définit les parties de l'application pouvant être impactées par le CSS d'un composant.

Par défaut Angular restreint le style défini dans un composant pour qu'il ne puisse pas affecter d'autres composants.

Mais vous pouvez configurer ce paramètre et définir l'encapsulation qu'il vous faut. Pour cela, Angular fournit 3 stratégies d'encapsulation.

Comment configurer le mode d'encapsulation ?

Pour configurer un mode d'encapsulation, repérez le décorateur @Component d'un de vos composants puis ajoutez le paramètre encapsulation avec une des 3 valeurs suivantes :

  • ViewEncapsulation.Emulated
  • ViewEncapsulation.Native
  • ViewEncapsulation.None

Comme ceci :

1
2
3
4
5
6
7
8
import {ViewEncapsulation} from '@angular/core';

@Component({
  selector: 'my-component',
  templateUrl: 'my-component.component.html',
  encapsulation: ViewEncapsulation.None
})
class MyComponentComponent {}
Exemple de personnalisation de la view encapsulation

Les 3 méthodes d'encapsulation

Voyons maintenant comment fonctionnent les 3 différentes méthodes d'encapsulation fournies par Angular.

Emulated (par défaut)

Le mode par défaut d'Angular est : Emulated. Tous les navigateurs ne supportent pas le shadow DOM, donc les équipes d'Angular ont implémenté une encapsulation "manuelle" qui ne repose pas sur le shadow DOM.

Pour encapsuler "manuellement", Angular va ajouter un attribut unique sur tous les éléments du composant, puis modifier les sélecteurs CSS du composant afin qu'ils ne soient appliqués qu'à cet attribut.

Exemple :

1
2
3
4
5
6
<hero-details _nghost-pmm-5>
  <h2 _ngcontent-pmm-5>Mister Fantastic</h2>
  <hero-team _ngcontent-pmm-5 _nghost-pmm-6>
    <h3 _ngcontent-pmm-6>Team</h3>
  </hero-team>
</hero-details>

Dans cette image, vous pouvez voir les attributs ajoutés par Angular.

Tous les élements ayant un lien avec le composant hero-details sont marqués avec l'attribut _ngcontent-pmm-5 ou _nghost-pmm-6. Tandis que tous les éléments ayant un lien avec hero-team sont marqués _ngcontent-pmm-6 ou _nghost-pmm-6.

Remarquez que hero-team est marqué à la fois comme host pmm-6 et content pmm-5. Il pourra donc être atteint par du CSS venant de hero-details en tant qu'élément contenu, ou alors par du CSS venant de hero-team qui ciblerait l'élément hôte.

En parallèle d'avoir ajouté ces attributs, Angular a modifié vos sélecteurs CSS dans les 2 composants pour cibler les attributs voulus. Tous les sélecteurs de hero-details ciblent un attribut terminant par pmm-5, il est donc impossible que le CSS d'hero details atteigne un autre endroit du code.

Cela n'empêche pas notre composant d'être ciblé par du CSS global, non encapsulé.

ShadowDom (natif)

L'API Shadow DOM est un standard, malheureusement pas très stable entre les différents navigateurs, qui sert justement à encapsuler des sections de DOM.

Le shadow DOM est un sous-DOM (un morceau de DOM) qui fonctionne en autonomie, sans être directement relié au DOM. On peut décider de "fermer" un shadow DOM pour l'isoler complêtement et qu'aucun style extérieur ne puisse l'atteindre (et vice-versa). La méthode Shadow DOM demande à Angular d'utiliser des shadow DOMs pour encapsuler le style de vos composants.

Notez cependant qu'à l'inverse du mode Emulated, les styles globaux n'affecteront pas un tel composant, le composant étant complètement isolé du reste du DOM.

À la compilation, Angular va référencer votre composant en tant que Web component natif et le HTML généré utilisera le standard Shadow DOM.

Exemple :

1
2
3
4
5
6
7
8
9
10
<my-component>
  #shadow-root
  <style>
  .random {
    height: 80px;
  }
  </style>
  <div class="random">
  </div>
</my-component>

L'annotation #shadow-root est ajoutée par le navigateur pour signaler que l'élément placé juste en dessous (ici la balise style) est l'élément racine d'un Shadow DOM.

Les règles CSS ne pourront donc pas être connues du reste de la page car elle n'en a pas connaissance.

None

Le mode None va faire en sorte qu'Angular désactive complètement la fonctionnalité d'encapsulation. Donc une règle CSS venant du composant réglé sur none, pourra impacter tout le reste de l'application (sauf potentiellement un composant ShadowDOM car il restera isolé).

Le style sera visible depuis la balise <head> de la page HTML au sein d'une balise <style> globale.

Il est fortement déconseillé d'utiliser cette méthode car à cause de la portée du style, elle rend le style difficile à maintenir et peut créer des effets de bord indésirables. Prenez bien le temps de mesurer les impacts si vous choisissez cette méthode.

Pourquoi configurer la view encapsulation ?

La plupart du temps, vous ne devriez pas toucher à cette configuration. Car l'encapsulation du style par composant est la méthode la plus sûre et la plus maintenable.

Mais dans certains cas, il est pertinent voire nécessaire de changer ce comportement.

Imaginez par exemple que vous devez customiser un composant venant d'une librairie, à un endroit précis du code. L'encapsulation par défaut vous empêcherait d'atteindre cet élément car il est déclaré en dehors de votre composant.

Utiliser le sélecteur ::ng-deep

La pseudo-classe ::ng-deep désactive complètement l'encapsulation de la vue pour la règle mentionnée. Tout style appliqué dans une règle marquée ::ng-deep devient global.

Lorsque vous devez contourner les règles d'encapsulation, préférez utiliser ::ng-deep au mode ViewEncapsulation.None, car ::ng-deep n'impactera qu'une règle CSS au lieu de tout le fichier.

Si vous devez utiliser ::ng-deep, vous voudrez généralement le combiner avec :host. Ainsi, vous pourrez impacter les éléments enfants de votre composant, mais pas le reste de l'application.

1
2
3
:host ::ng-deep h3 {
  font-style: italic;
}

Cet exemple cible tous les éléments h3 contenus dans ce composant ou dans un de ses composants enfant.

La documentation Angular marque ::ng-deep comme étant déprécié, mais aucune alternative viable n'existe à ce jour. Il est juste conseillé de s'en servir le moins possible.

Conclusion

J'espère que cela vous aidera a voir plus clair sur la view encapsulation. N'hésitez pas à suggérer une amélioration en commentaire !

Téléchargez votre Starter Kit Angular

Starter Kit Angular

En souscrivant vous recevrez :

  • Une roadmap d'un développeur Angular
  • Un cookbook Angular des commandes les plus utiles
  • Un extrait de formation

100% gratuit.

Auteur

image auteur
Lucas BENTO-VERSACE Alternant chez Codewise / Étudiant en développement web lucas.bentoversace@ynov.com
"Alternant chez Codewise, passioné par l'informatique et les technologies depuis mon plus jeune âge. J'ai découvert le monde du web et depuis je ne m'en lasse pas ! Fan de jeux vidéos, de sports et de musiques. "