🧢

WebComponentsを支える技術〜Shadow DOM〜

2021/02/15に公開

WebComponentsをつかってカスタムHTMLを実装するにあたり、Shadow DOMについて調べたのでまとめてみました。

Shadow DOMについて、一言で

  • Shadow DOMは、DOM要素をカプセル化するための手段

どうしてDOMをカプセル化したいのか

HTML文書内にあるすべてのDOMは、JavaScriptで取得&操作できます。また、すべてのDOMはCSSで修飾できます。いわばグローバル空間に存在しているのと同じです。

しかし開発をしていると、JavaScriptで操作したくない要素・CSSを効かせたくない要素がでてきます。特にCSSの方は深刻で、グローバルCSSをひたすら上書きしていく悲しい作業に強いられることがまれによくあります。

「DOM要素をカプセル化して、スコープの外のJavaScriptやCSSから守りたい。この手で」

そのとき、Shadow DOMが役に立ちます。

Shadow DOMとは

カプセル化されたDOMのことです。
通常のDOMをホストとし、その下にカプセル化したDOMをぶら下げるという使い方をします。

ホスト用のDOMを「Shadow host」、カプセル化したDOMのrootを「Shadow Root」といいます。


[出典] https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM

通常のDOMをホスト(Shadow Host)にし、その下にShadowRootをぶら下げ、
更にその下に各種要素をぶら下げていく。そうすると、ShadowRoot以下がカプセル化される、という仕組みです。

Shadow DOMのつくりかた

Elementオブジェクトに「attatchShadow」というプロパティがあるので、それを使います。

// ShadowRootの生成
const element = document.getElementById('host');
const shadowRoot = element.attachShadow({mode: 'closed'});
// 外部のJavaScriptからカプセル化したいときは、modeをclosedにする。
// closedにするとshadowRootへの参照がnullになる

// ShadowRootにカプセル化したい要素をぶら下げる
shadowRoot.innerHTML = '<h1>隠れていたい</h1>'

Chromeのinspectでみると、このように表示されます。

開くと↓このように見えます。

カプセル化されているか確かめ(その1)

上で生成したShadowRootが、外部のCSSに影響されないことを確かめてみましょう。
以下のように、HTMLとglobalに効くCSSを定義します。

<h1>hello</h1>
<div id="host"><!-- <h1>隠れていたい</h1> というShadowDOMが挿入される --></div>
h1 {
  background-color: red
}

結果

無事、global CSSから逃げられました。

カプセル化されているか確かめ(その2)

上で生成したShadowRootが、外部のJavaScriptから参照されないことを確かめてみます。

const element = document.getElementById('host');
console.log(element.shadowRoot) // null

外部からShadowRootが取得できないことがわかりました。
これでJavaScriptから逃げることができました。

まとめ

DOMをカプセル化するだけなら、ShadowDOMで十分だとわかりました。
globalなCSSやJavaScriptに影響されたくないような外部のコンテンツを埋め込むときに使えそうです。

Discussion