Shadow Root 内の指定の要素にスタイルを当てたい
- カテゴリ:
- JavaScript
- CSS
- コメント数:
- Comments: 0
◆ 最近は ::part を使う方法
◆ Shadow Root の中身を作るときに公開するよう part 属性をつけてる要素にのみスタイルをつけれる
◆ 公開されてないと手段がない
◆ Shadow Root が open なら直接 adoptedStyleSheets を追加する手はあるが closed だと不可能
◆ Shadow Root の中身を作るときに公開するよう part 属性をつけてる要素にのみスタイルをつけれる
◆ 公開されてないと手段がない
◆ Shadow Root が open なら直接 adoptedStyleSheets を追加する手はあるが closed だと不可能
ある Custom Element の中の Shadow Root 内の特定要素を非表示にしたいです
たしか ::shadow みたいのがあったっけと思って調べたらすでに使えなくなってたようです
/deep/ というのもありましたが これも同じく使えなくなっていました
使い方を見てみると セレクタとして書けるので CSS 変数よりは自由度が高く 特定の要素に対して好きにスタイルが当てれるようです
しかし 特定の要素というのはコンポーネント作成者が事前に決めたもののみです
使う側が 「こうしたい」 と思ったとしても 作成者がそれを想定した作りとしてない場合は ::part でスタイルを当てることはできません
コンポーネントのソースコードを書き換えるしかないです
要素を特定すればそれより下側の要素はセレクタで取れるのかと思って試してみると ::part で取得したものに追加のセレクタは適用できないようでした
このページの場合 a の水色のみスタイルが適用されます
b に .x でクラス指定していたり 子孫セレクタで span を指定していたりしますがどちらも効果なしです
Shadow DOM にアクセスできるので HTML を書き換えるでも style タグを追加でも自由にできます
最近だと adoptedStyleSheets を使うのが楽にできると思います
上に書いた例のページで下のスクリプトを実行すると Shadow Root 内のボタンの文字色を赤くできます
foo 要素の ShadowRoot は adoptedStyleSheets を使っていなかったので置き換えてますが 実際には使われてることを考慮して置き換えではなく push メソッドで追加のほうが良いです
モードを closed にして Shadow Root を作成し 参照できる方法が用意されてないと完全にどうしようもないです
当初の目的だった要素の非表示ですが Shadow DOM が closed な Shadow Root の中だったので実現できませんでした
class の private プロパティもそうですが 完全にアクセス不可って使う側から不便になるだけなので やめてほしいですね
これまでの DOM や JavaScript はオープンなものだったので 不具合の回避や 本来サポートされてない機能の追加をライブラリ自体に手を加えずに使用する側から行えたのにそういうことができなくなります
通常利用を想定していなくてアップデートで変わるかもということさえ伝えてくれたら十分で それらを理解した上でやるという手段を残しておいて欲しいものです
昔の方法は使えなくなってた
これまではコンポーネント側が指定する CSS 変数に設定を書いておくと 反映してくれるくらいにしかカスタムしてませんでしたたしか ::shadow みたいのがあったっけと思って調べたらすでに使えなくなってたようです
/deep/ というのもありましたが これも同じく使えなくなっていました
::part()
今は ::part を使うようです使い方を見てみると セレクタとして書けるので CSS 変数よりは自由度が高く 特定の要素に対して好きにスタイルが当てれるようです
しかし 特定の要素というのはコンポーネント作成者が事前に決めたもののみです
使う側が 「こうしたい」 と思ったとしても 作成者がそれを想定した作りとしてない場合は ::part でスタイルを当てることはできません
コンポーネントのソースコードを書き換えるしかないです
要素を特定すればそれより下側の要素はセレクタで取れるのかと思って試してみると ::part で取得したものに追加のセレクタは適用できないようでした
<script type="module">
const foo = document.getElementById("foo")
const shadow_root = foo.attachShadow({ mode: "open" })
shadow_root.innerHTML = `
<div part="a">A</div>
<div part="b">B</div>
<div part="b" class="x">
<span>C</span>
<button>button</button>
</div>
`
</script>
<style>
#foo::part(a) {
background: aqua;
}
#foo::part(b).x {
background: orange;
}
#foo::part(b) span {
background: yellow;
}
</style>
<div id="foo"></div>
このページの場合 a の水色のみスタイルが適用されます
b に .x でクラス指定していたり 子孫セレクタで span を指定していたりしますがどちらも効果なしです
抜け道
Shadow Root が公開されていれば抜け道はありますShadow DOM にアクセスできるので HTML を書き換えるでも style タグを追加でも自由にできます
最近だと adoptedStyleSheets を使うのが楽にできると思います
上に書いた例のページで下のスクリプトを実行すると Shadow Root 内のボタンの文字色を赤くできます
const sheet = new CSSStyleSheet()
sheet.replaceSync(`
.x button {
color: red;
}
`)
const foo = document.getElementById("foo")
foo.shadowRoot.adoptedStyleSheets = [sheet]
foo 要素の ShadowRoot は adoptedStyleSheets を使っていなかったので置き換えてますが 実際には使われてることを考慮して置き換えではなく push メソッドで追加のほうが良いです
closed はやめてほしい
上記の方法が使えるのは Shadow Root が公開されてるかアクセス手段が用意されてる場合のみですモードを closed にして Shadow Root を作成し 参照できる方法が用意されてないと完全にどうしようもないです
当初の目的だった要素の非表示ですが Shadow DOM が closed な Shadow Root の中だったので実現できませんでした
class の private プロパティもそうですが 完全にアクセス不可って使う側から不便になるだけなので やめてほしいですね
これまでの DOM や JavaScript はオープンなものだったので 不具合の回避や 本来サポートされてない機能の追加をライブラリ自体に手を加えずに使用する側から行えたのにそういうことができなくなります
通常利用を想定していなくてアップデートで変わるかもということさえ伝えてくれたら十分で それらを理解した上でやるという手段を残しておいて欲しいものです