この記事は webcomponents.org の記 事とのクロスポス トです。

Shadow DOM を利用すると、DOM 要素に、ウェブページの他の部分とは切り離された、 ノード内だけで有効なスタイルやマークアップを含んだ DOM ツリーを追加することがで きます。この記事と動画では、この Shadow DOM について解説します。

Shadow DOM とはなにか? #

こちらは HTML5 の video タグで表示された動画です。ご覧頂けるとお分かりのように、 コードは video タグのみという単純さでありながら、動画そのものだけでなく、制御用 の UI も表示することができています。

<video src="http://craftymind.com/factory/html5video/BigBuckBunny_640x360.mp4" controls></video>

実は Chrome で DevTools を開いて、'Show user agent shadow DOM' オプションを on にすると、この制御用 UI がどのようにできているか確認することができます。

この制御用 UI が、実際は HTML でできていることがお分かりでしょうか?これが Shadow DOM の一例です。

Shadow DOM が素晴らしいのは、実はこの機能がウェブ開発者にも使える、ということで す。

Shadow DOM の構造 #

Shadow Root を持った要素は Shadow Host と呼ばれます。Shadow Root は通常の DOM 要 素と同様に扱えるため、任意のノードを追加することもできます。

Shadow DOM では、すべてのマークアップと CSS が要素内にスコープされます。言い換え ると、Shadow Root 内で定義された CSS は親ドキュメントに影響を与えず、親ドキュメ ントの CSS が誤って Shadow Root 内に影響を与えることもありません。

Shadow DOM の作り方 #

Shadow DOM を作るには、任意の DOM 要素に対して .createShadowRoot() を呼び出 し、Shadow Root を作ります。この Shadow Root オブジェクトに要素を足していくこと で、Shadow DOM を構築していくことができます。

<div id="host"></div>
var host = document.querySelector('#host');
var root = host.createShadowRoot(); // Shadow Root を作る
var div = document.createElement('div');
div.textContent = 'This is Shadow DOM';
root.appendChild(div); // Shadow Root に要素を追加

Shadow Root に追加された要素はクエリすることもできません。この場合、 document.querySelector('#host div') は null になります。

Shadow DOM 内に Shadow Host のコンテンツを表示する #

Shadow DOM 内に Shadow Host の子要素を表示したい場合があると思います。例えば Shadow DOM によってスタイルを与えられているネームタグのような要素を考えてみま しょう。外部からの入力で文字だけ変更できると便利ですよね。

<div id="nameTag">Bob</div>

これを実現するには、<content> 要素を用います。

var host = document.querySelector('#host');
var root = host.createShadowRoot();
var content = document.createElement('content');
content.setAttribute('select', 'h1'); //<content select="h1"></content>
root.appendChild(content);
<div id="host">
<h1>This is Shadow DOM</h1>
<div>

<content> 要素に select 属性として Shadow Host から取り上げたいノードを指し 示す CSS セレクタを与えることで、その要素が <content> の位置に挿入されます。

なお、<content> 要素で指定できるのは、Shadow Host の直接の子孫となる要素を示す CSS セレクタのみです。つまり以下のように、子孫の子孫を示すようなことはできませ ん。

<div id="host">
<div class="child">
<h1>This is Shadow DOM</h1>
</div>
</div>

<content select=".child h1"></content> // これはダメ

Template と組み合わせる #

Shadow DOM は素晴らしいですが、構築のためにいちいち命令的に DOM ツリーを構築する JavaScript を書くのは楽ではありませんし、デザイナーが入ってくる余地もありませ ん。

そこで登場するのが Template 要素です。Template 要素を活用することで、Shadow DOM の構築が宣言的に行いましょう。Template 要素については、前回のポス トを参考にして下 さい。

<template id="template"> // <template> の中身が Shadow DOM になる
<style>
...
</style>
<div id="container">
<img src="http://webcomponents.org/img/logo.svg">
<content select="h1"></content> // h1 をここに挿入
</div>
</template>

<div id="host">
<h1>This is Shadow DOM</h1>
</div>
var host = document.querySelector('#host');
// Shadow Root を作る
var root = host.createShadowRoot();
var template = document.querySelector('#template');
// <template> をコピー
var clone = document.importNode(template.content, true);
// Shadow Root に追加
root.appendChild(clone);

実際のコードはこちらでご覧頂けます。

ブラウザサポート状況 #

Shadow DOM は 2014 年 10 月現在 Chrome, Opera, フラグ付きなら Firefox でもサポー トされています。最新のサポート状況は chromestatus.com または caniuse.com で チェックしてみて下さい。ポリフィルとして  platform.js (2014 年 11 月から webcomponents.js に名称変更予 定) も利用できます。

まとめ #

いかがでしたでしょうか?Shadow DOM は今回記事にした内容の他にも、外部からのスタ イリングやイベントの扱い方、複数の Shadow Root の扱い方など、非常に複雑な仕様が 盛りだくさんです。

Shadow DOM についてより詳しく知りたいという方は、下記のドキュメントを参考にして ください。