web-dev-qa-db-ja.com

shadow-root要素のスタイルをオーバーライドする

シャドウ要素で見つかったスタイルを変更する方法はありますか?具体的には、cssclassにあるいくつかのプロパティを拡張/上書きしますか?私は Beanote というchrome-extensionを使用していますが、これは4月(2017)から更新されておらず、修正したい厄介なバグがあります。 1行のcssでパッチが十分に当てはまることがわかりましたが、シャドウ要素自体の内部に入り、開発ツールでこれらのスタイルを直接編集せずに適用することに途方に暮れています。

私はこの方法を探しています:

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

これを上書きするには:

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


オンラインで見つけたほとんどのリソースで、shadow-root override styleまたはedit shadow-root stylingに関係がありました:Hostこれは、これが意図されている場合、私のニーズや::shadow

12
Andrew

Shadow DOMの機能であるスタイルの分離のため、Shadow DOMスコープで適用されるグローバルCSSルールを定義することはできません。

CSS変数を使用することも可能ですが、シャドウコンポーネントに明示的に実装する必要があります(このサードパーティライブラリの場合はそうではありません)。

回避策は、スタイルのラインをシャドウDOMに直接注入することです。

//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 )

注意:Shadow DOM mode'open'に設定されている場合にのみ機能します。


2019年のChrome 73+およびOpera 60 +の更新

CSSStyleSheetオブジェクトを直接インスタンス化し、シャドウDOMまたはドキュメントに影響を与えることができるようになりました。

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

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');
  }

デフォルトで生成されたshadowRootスタイルを上書きする場合は、ページが完全にロードされた後にjs関数を呼び出す必要があります。

4
riguang zheng

以前の回答を拡張します。

外側のスタイルは、Shadow DOMで定義されたスタイルよりも常に優先されます。つまり、スタイリングしているコンポーネントを参照するグローバルスタイルルールを追加した場合です。参照: https://developers.google.com/web/fundamentals/web-components/shadowdom#stylefromoutside

それ以外の場合、これは要素のシャドウDOMがstyleSheetで埋め込まれているか、またはadoptedStyleSheetsを使用してスタイルシートを採用しているかに依存します。

要素が要素に埋め込まれている場合、addRuleまたはinsertRuleを使用して、既存のスタイルシートにルールを追加または挿入できます。これは、adopedStyleSheetsで追加されたスタイルシートでも機能します。

前の回答で述べたように、代わりに採用されたスタイルシートのリストに新しいスタイルシートを追加できます。これは、styleSheetが優先され、adoptedStyleSheetsは読み取り専用プロパティであるため、shadowRootにstyleSheetListが埋め込まれている場合にも機能します。

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

ホスティングアプリケーションからWebComponentをカスタマイズする問題を解決する良い、私見の方法を指摘しているので、コメントの1つで@Renatoによって与えられた答えを2番目にしたいと思います。

@Supersharpは、外部CSSルールがnotであるという事実に正しく、シャドウルートに伝播します。これは仕様によるものです。

CSS変数は良い方向ですが、私の個人的な経験からは、単一の使用法の値については少しやり過ぎです。そして、それらは前もってWebComponentでサポートされなければなりません。

伝播:Hostを介したプロパティ継承(@Renatoが述べたとおり)は、IMHOのAPIデザインに沿った完全に正しいパターンです。

  • カスタム要素(:Host 's)のCSSルールは、設計により外側のルールによってオーバーライド可能です
  • :Hostの子、Shadow DOMの内部コンテンツは、デフォルトまたは明示的なルールのいずれかで、:HostのCSSルールを継承する場合があります。

該当する場合は、CSSスタイルシートの挿入を検討する前にこのアプローチを採用することをお勧めします。また、openモードのみの制限を受けません。

もちろん、このアプローチは次の場合には役立ちません。

  • 内部要素は、:Hostから関連するルールを継承していません
  • WebComponentの構造は非常に複雑であるため、単一の:Hostですべてを支援することはできません

それでも、私自身の経験から、CSSルールをオーバーライドできることが望ましい単純なコンポーネントは、:Hostを介してルールを伝播する非侵入型パターンから多くの利益を得ることができます。

0
GullerYA