web-dev-qa-db-fra.com

Remplacer les styles dans un élément root-shadow

Existe-t-il un moyen de modifier les styles trouvés dans un élément d'ombre? Plus précisément, étendre/écraser certaines propriétés trouvées dans une classe css ? J'utilise une extension chrome appelée Beanote qui n'a pas été mise à jour depuis avril (2017) et il y a un bug embêtant que je voudrais corriger. J'ai trouvé qu'une ligne de CSS le corrige assez pour moi, mais je suis à la peine de l'appliquer sans entrer dans l'élément d'ombre lui-même et modifier directement ces styles dans les outils de développement.

Je cherche un moyen pour cela:

/*global css rule*/
.the-class-name { property-name: my-value; }

pour écraser ceci:

/* style tag inside the shadow-root */
.the-class-name { property-name: bad-value; }


La plupart des ressources que j'ai trouvées en ligne avec des requêtes impliquant shadow-root override style ou edit shadow-root styling avait quelque chose à voir avec :Host qui, s'il est destiné à cela, ne fonctionne pas pour mes besoins ou pour des fonctionnalités obsolètes comme ::shadow.

12
Andrew

En raison de l'isolement des styles, qui est une fonctionnalité de Shadow DOM, vous ne pouvez pas définir une règle CSS globale qui sera appliquée dans la portée de Shadow DOM.

Cela pourrait être possible avec des variables CSS mais elles devraient être implémentées explicitement dans le composant ombré (ce qui n'est pas le cas avec cette bibliothèque tierce).

Une solution de contournement consiste à injecter directement la ligne de style dans le DOM d'ombre.

//Host is the element that holds the shadow root:
var style = document.createElement( 'style' )
style.innerHTML = '.the-class-name { property-name: my-value; }'
Host.shadowRoot.appendChild( style )

NB: cela ne fonctionnera que si le Shadow DOM mode est défini sur 'open'.


mise à jour 2019 pour Chrome 73+ et Opera 60 +

Il est maintenant possible d'instancier directement un objet CSSStyleSheet et de l'affecter à un Shadow DOM ou à un document:

var sheet = new CSSStyleSheet
sheet.replaceSync( `.color { color: pink }`)
Host.shadowRoot.adoptedStyleSheets = [ sheet ] 
14
Supersharp

Exemple de changement de couleur de l'icône de sélection Ionic V4

document.querySelector('#my-select').shadowRoot.querySelector('.select-icon-inner').setAttribute('style', 'opacity:1');


ionViewDidEnter() {
    document.querySelector('#my-select').shadowRoot.querySelector('.select-icon-inner').setAttribute('style', 'opacity:1');
  }

Si vous souhaitez remplacer le style shadowRoot généré par défaut, vous devez alors appeler la fonction js une fois la page entièrement chargée.

4
riguang zheng

S'étendant sur les réponses précédentes.

Les styles extérieurs l'emportent toujours sur les styles définis dans le Shadow DOM, c'est-à-dire lorsque vous ajoutez une règle de style globale qui référence le composant que vous stylisez. Voir: https://developers.google.com/web/fundamentals/web-components/shadowdom#stylefromoutside

Sinon, cela dépendra si les éléments shadow DOM ont été incorporés avec un styleSheet, ou s'il a adopté une feuille de style en utilisant adoptedStyleSheets.

Si l'élément a été incorporé dans l'élément, vous pouvez ajouter ou insérer une règle dans la feuille de style existante à l'aide de addRule ou insertRule. Cela fonctionne également pour les feuilles de style ajoutées avec adopedStyleSheets.

Comme mentionné dans la réponse précédente, vous pouvez plutôt ajouter une nouvelle feuille de style à la liste des feuilles de style adoptées. Cela fonctionne également lorsque le shadowRoot contient un styleSheet incorporé, puisque adoptedStyleSheets a priorité et styleSheetList est une propriété en lecture seule.

assert(myElement.shadowRoot.styleSheets.length != 0);
myElement.shadowRoot.styleSheets[0].addRule(':Host', 'display: none;');

assert(myElement.shadowRoot.adoptedStyleSheets.length != 0);
`myElement.shadowRoot.adoptedStyleSheets[0].addRule(':Host', 'display: none;');`

const sheet = new CSSStyleSheet();
sheet.replaceSync(`:Host { display: none; }`);

const elemStyleSheets = myElement.shadowRoot.adoptedStyleSheets;

// Append your style to the existing style sheet.
myElement.shadowRoot.adoptedStyleSheets = [...elemStyleSheets, sheet];

// Or if just overwriting a style set in the embedded `styleSheet`
myElement.shadowRoot.adoptedStyleSheets = [sheet];
1
holmberd

Je voudrais appuyer une réponse donnée par @Renato dans l'un des commentaires, car elle souligne la bonne façon, à mon humble avis, de résoudre le problème de la personnalisation d'un composant Web à partir de l'application d'hébergement.

@Supersharp a raison dans le fait que les règles CSS externes se propagent pas dans la racine de l'ombre, c'est par conception.

Les variables CSS sont une bonne direction, mais d'après mon expérience personnelle, c'est un peu exagéré pour une valeur d'utilisation singulière, ET oui, elles DOIVENT être prises en charge par le WebComponent dès le départ.

Propagation les propriétés à travers le :Host Via héritage (exactement comme @Renato mentionné) est, à mon humble avis, le modèle parfaitement à droite aligné avec la conception de l'API:

  • Les règles CSS des éléments personnalisés (:Host) Sont, par conception, remplaçables par les règles externes
  • Les enfants de :Host, Le contenu interne du Shadow DOM, PEUVENT hériter des règles CSS du :Host, Par défaut ou par règle explicite - et cela aussi, par conception

Je dirais que, le cas échéant, cette approche serait mieux adoptée avant d'envisager l'injection de feuilles de style CSS, et ne souffre pas non plus de la limitation du mode open uniquement.

Bien sûr, cette approche n'aidera pas lorsque:

  • Les éléments internes n'héritent pas des règles pertinentes du :Host
  • La structure d'un WebComponent est assez complexe, de sorte qu'un seul :Host Ne peut tout simplement pas les aider tous

Pourtant, encore une fois d'après ma propre expérience, des composants simples avec des règles CSS pouvant être remplacées de manière souhaitable peuvent bénéficier beaucoup du modèle non intrusif de propagation des règles via :Host.

0
GullerYA