chocolamint
@chocolamint

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

カスタム要素における template 要素内の style 要素で指定した ::slotted セレクタのスタイルが外部の全称セレクタ(*)に負ける

解決したいこと

カスタム要素を定義して、内部でスタイルを指定しようとしています。しかし思った通りに適用されず困っています。

template 要素内で用意した slot に差し込まれる li 要素へスタイルを当てたいです(コードは後述)。しかし、別の箇所で指定されている、いわゆる「リセットCSS」である

* { margin: 0; padding: 0; }

というスタイルに邪魔され、margin / padding が設定できなくて困っています。

一般に、全称セレクタは詳細度が 0-0-0 であり、要素セレクタは 0-0-1 であると理解しているのですが、何故か全称セレクタの指定が要素セレクタの指定を打ち消してしまいます。

  • なぜ全称セレクタの指定が優先されてしまうのか
  • どのように解決するのが一般的な手法なのか

を知りたいです。

発生している問題・エラー

全称セレクタで指定された指定が優先されています。

  • 期待している結果: li 要素の文字が青になり margin30px 取られる
  • 実際の結果: li 要素の文字は赤く、margin0 のままである

image.png

開発者ツールでも全称セレクタの指定がより優先度の高いものとして表示されます(が、詳細度だけ見ると勝っているはずなので理由がよくわかりません。::slotted() であることが関係している?)。

image.png

Windows 10 の Chrome, Firefox で再現しています。バージョンはあまり関係なさそうなので割愛します。

該当するソースコード

https://codepen.io/chocolamint/pen/poMbYJd で再現可能です。

<my-custom>
  <li slot="items">テスト</li>
  <li slot="items">テスト2</li>
</my-custom>
<template id="tm">
  <ul>
    <slot name="items"></slot>
  </ul>
  <style>
    ::slotted(li) {
      margin: 30px;
      color: blue;
      /* 全称セレクタで指定のないスタイルはきちんと適用されるのでセレクタ自体は間違っていない? */
      background: #F0F0FF;
    }
  </style>
</template>
* {
  margin: 0;
  padding: 0;
  color: red;
}
customElements.define(
  "my-custom",
  class MyCustomElement extends HTMLElement {
    connectedCallback() {
      const template = document.querySelector("#tm").content;
      const shadowRoot = this.attachShadow({ mode: "open" });
      shadowRoot.appendChild(template.cloneNode(true));
    }
  }
);

自分で試したこと

2

1Answer

仕様書によると、カスケード規則は Origin and Importance の次に Context があります。つまり、詳細度より強い規則です。
その記述は以下のようになっています。

When comparing two declarations that are sourced from different encapsulation contexts, then for normal rules the declaration from the outer context wins, and for important rules the declaration from the inner context wins. For this purpose, [DOM] tree contexts are considered to be nested in shadow-including tree order.
CSS Cascading and Inheritance Level 5

二つの宣言が、異なるカプセル化されたコンテキストのソースであった場合、通常の宣言は外側が勝ち、!importantは内側が勝つ、と記述されているように読めます。

こちらが原因ではありませんか?

2Like

Comments

  1. @chocolamint

    Questioner

    ありがとうございます!!
    めちゃくちゃそれっぽいですね…!確認してみます!😭🙏すごく助かりました

  2. @chocolamint

    Questioner

    なんだかこの記述からすると、ウェブコンポーネントで内部に隠蔽したい DOM 要素のスタイルが存在する場合は !important ルールで強制することが想定されてそうに読めますね…🤔

Your answer might help someone💌