HTMLWebコンポーネントはShadowDOMスタイルを使用しません

Aug 15 2020

バニラWebコンポーネントまたはHTML要素を作成しました。2つのリンクが表示されるだけです。

物事をカプセル化するために、私はシャドウDOMを使用します。ただし、カプセル化されていないようです。DOMツリーでは、これは#shadow-root内にあります。

Webコンポーネントが、Webコンポーネントのテンプレートで提供したスタイルではなく、グローバルスタイルを使用するのはなぜですか?

テキストは赤で、緑になると思っていました。

class MyEl extends HTMLElement {
  constructor() {
    super();
    this.shadow = this.attachShadow({ mode: "open" });
  }

  connectedCallback() {
    const template = `
      <style>
        a {
          color: green;
        }
      </style>
      <slot></slot>`;
    this.shadow.innerHTML = template;
  }
}

window.customElements.define("my-el", MyEl);
a {
  color: red
}
  <my-el>
    <a href="example.com">Item1</a>
    <a href="example.com">Item2</a>
  </my-el>

回答

1 AlanDávalos Aug 17 2020 at 15:12

この質問にはすでに受け入れられている答えがありますが、スロットの子をshadowRootに移動することは、ほとんどのユースケースでは望ましくありません。

おそらくやりたいことは、::slotted()セレクターを使用することです。

::slotted()セレクターを介してスロットの子に適用されたスタイルは「デフォルト」スタイルとしてのみ機能し、ライトDOMでスタイルを使用することでオーバーライドできることに注意してください。

たとえば、スニペットの次の編集済みバージョンを確認してください。

ご覧のとおり、今回my-elは色とテキスト装飾スタイルの両方を適用して、(<a>)子をそのスロットのいずれかに固定しようとします。

ただし、ライトドムではa.special、色をオーバーライドするセレクターがあるため<a class="special">、は緑ではなく赤になります

class MyEl extends HTMLElement {
  constructor() {
    super();
    this.shadow = this.attachShadow({ mode: "open" });
  }

  connectedCallback() {
    const template = `
      <style>
        ::slotted(a) {
          color: green;
          text-decoration: none;
        }
      </style>
      <slot></slot>`;
    this.shadow.innerHTML = template;
  }
}

window.customElements.define("my-el", MyEl);
a.special {
  color: red
}
  <my-el>
    <a href="example.com">Item1</a>
    <a class="special" href="example.com">Item2</a>
  </my-el>

1 Danny'365CSI'Engelman Aug 15 2020 at 23:44

完全で詳細な説明は次のとおりです。:: shadowDOMスロットにネストされた子用のスロット付きCSSセレクター

TL; DR

リンクはlightDOMにあるため、そのDOM(コードではドキュメントDOM)によってスタイルが設定されます。
ノードをlightDOMからshadowDOMに移動することは1つの「解決策」です。しかし、あなたはその時スロットを使用していません。

参考までに、コードは次のように圧縮できます。

class MyEl extends HTMLElement {
  constructor() {
    super().attachShadow({ mode: "open" })
           .innerHTML = `<style>a{color:green}</style><slot></slot>`;

  }
}

window.customElements.define("my-el", MyEl);

StackOverflow Search:Custom Elements SLOTsで、 SLOT関連のその他の回答を見つけることができます。

KresimirPendic Aug 15 2020 at 19:57

この行を観察してください。たとえば、次のように要素をシャドウに移動/コピーする必要があります。

this.shadow.innerHTML = this.innerHTML + template;

インラインスタイルのみがshadowdom要素に適用されることを示すためにこれを追加しました..SDでコピーされたリンクはあなたのスタイルを使用しています:)

そのになりGLOBALグリーンはなりSHADOW要素

class MyEl extends HTMLElement {
  constructor() {
    super();
  }

  connectedCallback() {
    this.shadow = this.attachShadow({ mode: "open" });
    const template = `
      <style>
        a {
          color: green;
        }
      </style>
      <slot></slot>`;
    this.shadow.innerHTML = this.innerHTML + template;
  }
}

window.customElements.define("my-el", MyEl);
a {
  color: red
}
<my-el>
    <a href="example.com">Item1</a>
    <a href="example.com">Item2</a>
  </my-el>