2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

shadow DOMでもCSSのスコープを分離できない場合がある

Last updated at Posted at 2025-02-15

shadow DOMを使うとカプセル化されるため、外部CSSの影響を受けないと思っていました。
しかし 継承可能なプロパティー(colorやfont等) はshadow DOMの内部にも適用されるため、思った通りの表示にならないことがあります

上記の動作に気が付いた経緯

既存の古いWebアプリの一部にReact(+TailWind CSS)を埋め込んだ際、既存のCSSの影響を避けるためにshadow DOM内にrenderする仕組みを作りました。ところが、Tailwind CSSで指定した文字色にならない(古いWebアプリのCSSが適用されていた)という現象が起きたため原因の調査を行いました

ReactをShadow DOM内にrenderする+継承可能なプロパティーをリセットするコンポーネントを作成しました
https://qiita.com/murasuke/items/50d9327332cbd2d40794

shadow DOMのカプセル化の仕様

  • shadow DOM内部では、外部CSSのセレクターにマッチしない(外部CSSは適用されない)
  • しかし、継承プロパティについては外部のDOMからshadow DOMへ継承される

継承されるプロパティーと継承されないプロパティーについて

  • 継承される主なプロパティ(親要素を引き継いでも問題がないもの。主にテキスト関連)
    • color, font, visibility, line-heightなど
  • 継承されない主なプロパティー(見た目やレイアウトに関するスタイル)
    • text-decoration, background, border, margin, padding, width, heightなど

※つまり、shadow DOMのコンテナ要素に何らかのスタイルが継承されている場合、shadow DOM内部にもスタイルが継承され、フォントの色、フォントサイズなどが思った通りにならない場合がある、ということでした

確認用html

子要素に継承されるプロパティ(color)と、継承されないプロパティー(border)を用意し、セレクタで適用する箇所を変更して動作確認を行います

index.html
<!DOCTYPE HTML>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>shadow DOM inherit style</title>
  <style>
    /* この部分のセレクタを変更して動作を確認する */ {
      color : #d22; /* (子要素に)継承されるスタイル */
      border: medium dashed #2d2; /* 継承されないスタイル */
    }
  </style>
</head>
<body>
  <h1>shadow DOMの外&lt;h1&gt;</h1>
  <div id="host"></div>
  <script>
    // shadow DOMを作り<h1>を追加
    const host = document.querySelector("#host");
    const shadow = host.attachShadow({ mode: "open" });
    const span = document.createElement("h1");
    span.textContent = "shadow DOMの中<h1>";
    shadow.appendChild(span);
  </script>
</body>
</html>
  • DOMは以下のようになります(jsでshadow DOMを作り、その中に<h1>タグを追加している)

image-1.png

  • 上記サンプルではセレクターが無いため、<h1>のデフォルトで表示されます(構文エラーで無視される)

image-2.png

影響を受けない例

  • スタイルを<h1>に適用した場合、shadow DOM側はカプセル化されているため適用されません
selector-h1.html
  <style>
    /* h1に適用した場合、h1とその子要素にしか適用されないので、shadow DOMには影響しない */
    h1 {
      color : #d22; /* (子要素に)継承されるスタイル */
      border: medium dashed #2d2; /* 継承されないスタイル */
    }
  </style>

image.png

shadow DOMが外部CSSの影響を受ける例①

body要素に適用した場合はshadow DOMも子要素になります。そのため、継承されるプロパティ(color)はshadow DOM内部にも適用されます

selector-body.html
  <style>
    /* body要素に適用した場合、継承されるスタイルはshadow DOM内にも適用される */
    body {
      color : #d22; /* (子要素に)継承されるスタイル */
      border: medium dashed #2d2; /* 継承されないスタイル */
    }
  </style>
  • colorがshadow DOM内にも適用されました(borderは<body>のみに適用されています)

image-3.png

shadow DOMが外部CSSの影響を受ける例②

全称セレクタ(*)の場合、全てのタグに適用されます

universal-selector.html
  <style>
    /* 全称セレクタの場合、全てのタグに適用されるため継承しないスタイルも反映される */
    * {
      color : #d22; /* (子要素に)継承されるスタイル */
      border: medium dashed #2d2; /* 継承されないスタイル */
    }
  </style>
  • colorがshadow DOM内にも適用されます

image-4.png

  • borderがshadow DOM内の<h1>に適用されているように見えますが、これはshadow DOMのコンテナに対してborderが付与されたものです

image-5.png

  • shadow DOM内の<h1>には継承されていないので、スタイルが淡色表示になっています

image-6.png

shadow DOM側への適用を回避(取り消し)するには?

shadow DOMにCSSを追加して、プロパティー(スタイルの指定)を初期値にもどすことができます

全てのプロパティー(all)に対し、initialを指定することでブラウザの初期値に戻します

プロパティ 説明
initial 仕様で決められた初期値にもどす(黒色に戻る)
revert ブラウザが適用する初期値に戻す(この例で適用すると、ブラウザは初期値がないため、結果としてinherit同様、親のプロパティを引き継いでしまう)
inherit 親要素の値を引き継ぐ
unset 継承するプロパティの場合は inherit、継承しないプロパティは initial と同じ
avoid-inherit.html
  <script>
    // shadow DOMは外部のCSSの影響を受けないはずだが、(コンテナに)継承されたプロパティーは適用される
    const host = document.querySelector("#host");
    const shadow = host.attachShadow({ mode: "open" });

    // shadow DOM側で継承を取り消す(デフォルトへ戻す)スタイルを追加する
    // :hostは、CSSの擬似クラスで、shadow DOM のシャドウホスト(ルート)を選択する
    const sheet = new CSSStyleSheet();
    sheet.replaceSync(`
      :host {
        all: initial;
      }
    `);
    shadow.adoptedStyleSheets = [sheet];

    const span = document.createElement("h1");
    span.textContent = "shadow DOMの中<h1>";
    shadow.appendChild(span);
  </script>

shadow DOM内のスタイルが初期値に戻りました

image-7.png

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?