226 votes

Quoi utiliser à la place de ::ng-deep

Je tente de styliser un élément placé par la sortie du routeur dans Angular et je veux m'assurer que l'élément généré obtient une largeur de 100%

De la plupart des réponses, je vois que je devrais utiliser le sélecteur::ng-deep, mais selon les docs d'Angular, il est en voie d'obsolescence. Y a-t-il une alternative à ::ng-deep?

9 votes

::ng-deep ne va nulle part. Ce sera toujours un paramètre que vous pouvez activer. Ils ne peuvent absolument pas le supprimer maintenant sans une réaction massive de la communauté. Regardez combien de résultats reviennent pour cette recherche github.com/search?q=%3A%3Ang-deep&type=Code - c'est comme dire que la propriété css !important va disparaître

0 votes

Je ne sais pas - j'ai effectué une recherche à l'échelle du projet par curiosité dans notre mono-repo (plusieurs applications d'entreprise assez grandes) et je n'ai trouvé que 69 références. J'ai l'impression que c'est certainement une refonte acceptable pour sortir de l'obsolescence et je le ferais volontiers chaque fois qu'ils proposent une alternative. De plus, !important occupe une place importante dans la spécification CSS alors que ::deep n'était toujours qu'une proposition.

222voto

dudewad Points 1146

En ce qui concerne mes recherches, je n'ai pas trouvé de remplacement pour ng-deep ou les autres alternatives applicables. Cela est dû, je pense, au fait que l'équipe Angular se conforme à la spécification du shadow dom du W3C, qui incluait initialement des sélecteurs tels que deep. Cependant, le W3C a depuis supprimé cette recommandation, sans la remplacer. Jusqu'à ce que cela se produise, j'imagine que l'équipe Angular continuera de maintenir ::ng-deep et ses alternatives disponibles, mais dans un état obsolète en raison de l'état en attente des ébauches du W3C. Je ne peux pas prendre le temps de trouver la documentation pour étayer cela dès maintenant, mais je l'ai vu récemment.

En résumé : continuez à utiliser ::ng-deep et ses alternatives jusqu'à ce qu'un remplacement soit créé - l'obsolescence n'est qu'un avertissement précoce pour que les gens ne soient pas surpris lorsque le changement réel se matérialise.

-- MISE À JOUR --

https://drafts.csswg.org/css-scoping-1/ Voici la proposition d'ébauche si cela vous intéresse. Il semblerait qu'ils travaillent sur un ensemble robuste de sélecteurs pour les éléments dans un arbre shadow dom ; c'est cette spécification, une fois approuvée, qui, je pense, informera le clone Angular, s'il existe même (c'est-à-dire qu'Angular pourrait ne pas avoir besoin de mettre en œuvre ses propres sélecteurs une fois que cela sera disponible dans les navigateurs).

0 votes

Je suis d'accord avec cela, mais je ne recommanderais pas d'écrire de nouveau code délibérément en utilisant des fonctionnalités de framework obsolètes (et de navigateur).

8 votes

Je ne le voudrais pas non plus. Mais il n'y a pas d'alternative, ce qui, je pense, est assez clairement expliqué ici. Avez-vous des suggestions pour remédier à cela?

1 votes

La seule alternative à laquelle je peux penser rapidement serait de refactoriser l'emboîtement des composants, ce qui pourrait demander plus de travail que vous n'avez le temps pour mais pourrait apporter d'autres avantages...

90voto

J. Lenthe Points 226

L'alternative simple et facile à un style profond est un style commun utilisant le sélecteur d'éléments du composant parent. Donc si vous aviez ceci dans hero-details.component.css :

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

Cela deviendrait ceci dans styles.css :

app-hero-details h3 {
  font-style: italic;
}

Essentiellement, un style profond est un style non encapsulé, donc il me semble conceptuellement plus proche d'un style commun que d'un style de composant. Personnellement, je n'utiliserais plus de styles profonds. Les changements de rupture sont normaux dans les mises à jour majeures et la suppression de fonctionnalités obsolètes est autorisée.

4 votes

Wow, je me sens bête maintenant. Merci ! Venant d'autres frameworks front-end, je pensais que c'était impossible

2 votes

C'est vraiment utile. C'est dommage que ::ng-deep ait été obsolète pendant si longtemps sans avoir de remplacement ( :host::ng-deep fonctionne comme prévu, mais je ne veux pas utiliser des éléments obsolètes).

3 votes

Je suis confus, comment cela doit-il fonctionner? Si vous spécifiez le app-hero-details h3 { ... } dans le parent, il est encapsulé et n'affectera pas le h3 dans le composant enfant. Si vous suggérez d'utiliser ceci dans les styles partagés en général, alors d'accord, mais je ne crois pas que ce soit la bonne façon de le faire.

36voto

AliF50 Points 211

Pour contourner le ::ng-deep obsolète, je désactive généralement ViewEncapsulation. Bien que ce ne soit pas la meilleure approche, cela m'a bien servi.

Pour désactiver ViewEncapsulation, faites ce qui suit dans votre composant :

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

@Component({
  selector: 'app-header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.scss'],
  encapsulation: ViewEncapsulation.None
})

export class HeaderComponent {

}

Cela rendra les styles .scss de ce composant globaux à toute l'application. Pour ne pas permettre aux styles de remonter dans la hiérarchie vers les composants parent et frère, enveloppez tout le scss avec le sélecteur comme suit :

app-header {
  // vos styles ici et tous les styles des composants enfants peuvent se trouver ici
}

À présent, les styles spécifiés ici descendront vers les composants enfants, donc vous devez être très précis avec vos sélecteurs CSS et faire attention lorsque vous ajoutez du CSS (peut-être ajouter le sélecteur enfant spécifié dans votre application Angular et ensuite ses styles).

Je dis que ce n'est pas la meilleure approche en raison du paragraphe précédent, mais cela m'a bien servi.

35 votes

Ceci est juste une solution de contournement et si vous avez un projet énorme, désactiver ViewEncapsulation causera beaucoup de dommages en permettant à ces styles de s'infiltrer dans tous les composants. Cette fonctionnalité doit être utilisée avec sagesse et pleine compréhension

6 votes

@mpro Je comprends, c'est pourquoi j'ai donné l'avertissement et dit que ce n'est pas la meilleure approche et que vous devez faire attention à tous les détails et être très précis. Pour moi, cette approche a bien fonctionné jusqu'à présent. ::ng-deep est marqué pour la désuétude et c'est un contournement.

2 votes

Honnêtement, je pense que c'est une conclusion horrible à laquelle arriver si vous avez fait cela à cause de la dépréciation menacée. Oui, je sais que vous en avez pris connaissance, mais je pense vraiment que vous vous tirez une balle dans le pied en faisant cela. L'encapsulation de la vue est si utile pour de nombreuses raisons. Cependant, ce n'est pas aussi grave que la personne de l'équipe angulaire qui l'a dépréciée sans solution de contournement logique, entraînant beaucoup de confusion. À la fin de la journée, vous écrivez toujours du code pour un navigateur Web - pas pour une sorte de moteur Angular propriétaire.

34voto

Josh Guzman Points 375

Comme quelqu'un l'a déjà dit, si vous utilisez une bibliothèque tierce, il est pratiquement impossible d'éviter le ::ng-deep de temps en temps.

Jetons un coup d'œil à quelques alternatives

  1. Utiliser ViewEncapsulation.None

    @Component({ selector: 'app-example', templateUrl: './example.component.html', styleUrls: ['./example.component.scss'], encapsulation: ViewEncapsulation.None })

Sachez que le fait de casser l'encapsulation du composant rendra les styles globalement disponibles. Je peux penser à 2 façons d'éviter les collisions et les bizarreries CSS :

  • Enveloppez le template de votre composant avec une classe. Ainsi, example.component.html devrait ressembler à ceci:

Maintenant, comme il n'y a pas d'Encapsulation, vous pouvez modifier le composant tiers en ciblant leurs classes. Cela dit, example.component.scss devrait ressembler à ceci:

.app-example-container {
/* Tout le code CSS va ici */
.mat-tab-group .mat-tab-label {color: red;}
}
  • ou utilisez le nom de balise du composant comme enveloppe. Par exemple:

    app-example { / Tout le code CSS va ici / .mat-tab-group .mat-tab-label {color: red;} }

  1. Utiliser des styles globaux

Aussi simple que d'ajouter un nouveau fichier CSS à votre tableau de styles de votre fichier de configuration angular.json. Sachez que cela deviendra éventuellement de plus en plus difficile à maintenir. Personnellement, j'éviterais cette option ou l'utiliserait en dernier recours :)

  1. Utiliser une directive

Je suis d'accord que c'est un peu douloureux car vous ne pouvez pas inclure Styles dans une directive (de la même manière que vous le faites dans un composant), mais cela peut parfois être pratique. Vous pourriez également utiliser un composant pour appliquer les styles de la même manière que l'équipe Angular Material l'a fait avec les boutons

  1. :host ::ng-deep

Vous connaissez déjà celui-ci, je voulais juste préciser que l'utiliser avec le sélecteur hôte est la manière recommandée par Angular pour éviter les éventuelles collisions de styles.

Une note personnelle pour le futur : https://angular.io/guide/component-styles
C'est le premier endroit où regarder pour les alternatives officielles/manières de procéder

  1. Encouragez les auteurs de bibliothèques à utiliser des variables CSS que vous pourriez personnaliser depuis le composant parent ou les parties ombrées (quand c'est possible). L'équipe Ionic a fait un excellent travail à ce sujet. Pour une explication plus détaillée, vous pouvez consulter ici

Édition 1. Comme @beppe9000 l'a mentionné dans un commentaire, ::ng-deep est une chose d'Angular. Même si l'équipe Angular supprimait cette fonctionnalité demain, votre application déjà déployée continuerait de fonctionner. La confusion est apparue à cause de l'ancien /deep/ modificateur.

1 votes

Mais que vas-tu faire de tes projets précédents lorsque le ::ng-deep ne sera plus pris en charge par les navigateurs ? N'est-ce pas compilé/polyfilled par Angular CLI donc il n'y a pas d'intervention du navigateur ? Très bonne réponse d'ailleurs.

0 votes

Cela est en fait rendu dans le fichier CSS, puis le navigateur applique les styles en conséquence. L'aliasing est possible (je pense) en utilisant :host /deep/ .mat-tab-label cela devrait être transformé en ::ng-deep. Pour être honnête, il semble que l'utilisation de l'alias soit plus pratique car le CLI peut le changer pendant le temps de compilation, mais vous devrez quand même effectuer un ng build et déployer à nouveau. Ma solution a été d'éviter ::ng-deep sur tous mes projets :)

0 votes

Oui, cela a du sens d'éviter la ré-déploiement

3voto

mrm1st3r Points 21

Il ne s'agit pas d'un remplacement général pour ::ng-deep, mais pour le cas d'utilisation décrit par l'auteur de la question:

Dans le cas particulier où vous souhaitez styliser l'élément inséré par un router-outlet, il existe une solution élégante en utilisant le sélecteur de voisin adjacent en CSS:

router-outlet+* {
  /* stylisation ici... */
}

Cela s'appliquera à tous les éléments qui sont des voisins directs d'un router-outlet.

Lecture complémentaire:
https://developer.mozilla.org/en-US/docs/Web/CSS/Adjacent_sibling_combinator
https://angular.io/guide/router#router-outlet

1 votes

Je ne recommanderais pas d'utiliser ce sélecteur. Cela semble ouvrir un véritable cauchemar de collisions, surtout lorsque votre application grandit. De plus, le sélecteur * est littéralement le sélecteur le plus lent en existence en CSS.

0 votes

@dudewad alors que le sélecteur * est le sélecteur le plus lent, il ne s'applique qu'au prochain sibling (+) littéralement, pas à toute la chaîne/arborescence, donc cela ne devrait faire qu'une différence nominale.

0 votes

@ErikPhilips Les sélecteurs CSS sont analysés de droite à gauche, donc c'est en réalité un scénario de pire cas.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X