先取り、Shadow DOM 第1回 Shadow DOMが生まれた理由
このシリーズではShadow DOMのコンセプトから実装例まで解説します。第1回目は、なぜShadow DOMという考え方が必要になってきたのか?という背景と、Shadow DOMの概念を解説します。
- カテゴリー
- JavaScript >
- Web Components
発行
Shadow DOMの仕様のうち「Decorator」は仕様から削除されました。(2016年9月現在)
はじめに
Shadow DOMとは、複雑化していくWebアプリケーション開発への取り組みを助けるためにGoogleから提案されているWeb Componentsと呼ばれる一連のコンセプトに繋がる仕様の一つです。
この記事を書いている2012年9月現在、まだW3C草案として公開されている段階であるため、随時更新されるか、他の仕様に置き換えられてしまうこともあるかもしれません。ですが、とても興味深い仕組みなので、現時点での情報を元に、ここで紹介をしてみたいと思います。
現状の問題点
Shadow DOMの概念をあれこれ説明する前に、まずは、どうしてShadow DOMが必要になってきたのか、という背景を説明していきましょう。
現在のWebサイトの多くは単一のページに複数の機能と、それを使うためのボタンを始めとする、さまざまなUIを含んでいます。
そんなUIに対してCSSで見た目のデザインを与え、JavaScriptで機能を与えるといった場合には、id属性やclass属性の値を利用して対象を指定するのが現在の手法です。
このとき、属性に使う値には気をつけておかないと、別の場所で使っている値と衝突してしまう可能性があります。
極端な例ですが、例えば、以下のようなコードを書いていると、思わぬ場所にCSSやJavaScriptが効いてしまい、めちゃくちゃな動作になってしまうかもしれません。
.button {
...
}
$('.button').button();
これを避けるためには、以下のコードのように長い名前を使って被らないようにしてみたり、特定の前置詞を付けてみたり、子孫セレクタで絞り込んだりといった工夫が考えられます。
おそらくみなさんも、一度くらいは似たような体験をされたことがあるのではないかと思います。
/* 長い名前を付けてみたり */
.latest-awesome-button {
...
}
/* 特定の前置詞を付けてみたり */
$('.js-button').button();
/* 子孫セレクタで絞り込んでみたり */
$('.where .is .the .button').button();
でも、意地悪なことを言えば、こんな努力を完璧にしたとしても、値が衝突しない保証は得られません。これから書く新しいコードが悪影響を及ぼさないかと、自分がいま考えたclass名を他の場所で使われていないか念入りに調べなければいけません。また、書き終えた後も、誰かがうっかり見た目や機能を上書きしてしまう心配は残ります。
それというのも、HTML要素はすべてHTML文書というたった一つの空間に同居していて、CSSやJavaScriptがHTML要素にアクセスするときにはいつも、ページ全体を基点に探してくるのが基本だからです。
現状の対応策
一応、Shadow DOMを使わなくても、この問題を解決することは可能です。
あるコードの断片を、親となるHTML文書から隔離しつつ、Webページに埋め込むことができる方法、iframe
です。
セキュリティ上の制限で、別のサイトを読み込むiframeの中身のHTMLには、親のHTMLが持っているJavaScriptやCSSからアクセスすることはできません。
実際にTwitterやFacebookなどから提供されているWebページ埋め込み用のボタンにはiframeが使われています。
<!--FacebookのLikeボタンのサンプル-->
<iframe src="//www.facebook.com/plugins/like.php?href=http%3A%2F%2Fwww.codegrid.net%2F&send=false&layout=standard&width=450&show_faces=true&action=like&colorscheme=light&font=arial&height=80" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:450px; height:80px;" allowTransparency="true"></iframe>
セキュリティのためというのもありますが、どんなWebページに埋め込まれても、Webページ側のCSSやJavaScriptの影響を受けずに既定のデザインと機能を提供する役目も果たしています。
ですが、iframeは小さなボタンやちょっとしたUIを設置する目的としては少し大げさで、柔軟さも足りません。そこで考えられたのがShadow DOMなのです。
Shadow DOM とは
Shadow DOMとは、一言でいえばDOMに対してカプセル化を提供する仕組みです。
カプセル化と聞くと、プログラムを普段書いている方は思い当たるかも知れません。
これはオブジェクト指向と呼ばれる、プログラミングの考え方を構成している概念の一つです。あるオブジェクトの中身に直接アクセスすることはできず、中身の詳細を覗くこともできず、オブジェクトを実装した人の用意した方法でしか、その中身にアクセスできない仕組みのことです。
Circleオブジェクトが持っているcolor、width、heightの値に直接アクセスすることはできない。Circleオブジェクトを実装した人が用意したsetColor()やsetSize()の機能を経由してのみアクセスができる。
カプセル化は大規模なアプリケーションを開発する際に重要なものとなります。そしてShadow DOMは、この概念をDOMに適用しようというものです。
DOMをカプセル化する
DOMをカプセル化するとはどういうことでしょうか。先ほど書いたカプセル化の説明を少し書き換えてみましょう。
「あるHTML要素の中身に直接アクセスすることはできず、中身の詳細を覗くこともできず、HTML要素を実装した人の用意した方法でしかその中身にアクセスできない仕組み」となります。
なんとなく想像できるでしょうか。具体的な状態としては、Webページ側のCSSルールは適用されず、JavaScriptからDOMを通じてアクセスすることもできず、Webインスペクタを使って要素内を調べることもできない、ということです。
Shadow DOMにはCSSもJavaScriptもアクセスできず、Web Inspectorなどの開発者ツールにも現れない。
あれができないこれができないと、不便になったような印象を与えるかもしれませんが、そうでもありません。
まず、HTML要素内に自分のコードが悪影響を及ぼす心配はありません。また、要素内がどうなっているか詳しく知る必要もなく、そのHTMLの断片を実装した人が公開している機能についてだけ知っておけば多くの人に簡単に扱える状態、ということでもあります。
Shadow DOMが活躍する場面
実際の開発の場面で、Shadow DOMはどんな貢献をすることができるでしょうか。
例えば、こんなシナリオを考えてみます。Webページのコーディングを引き受けたアリスは、部分的に複雑でリッチなUIを実装する必要があることに気づいて、その部分だけをUI実装の得意なボブにお願いしたとします。
UI実装が得意なボブは快くその仕事を引き受ける(イメージ)。
二人はclass名などが被らないようにネーミングルールを決めた後、アリスは意味的にも正しくなるような簡潔で綺麗なHTMLを仕上げました。
ボブもUIを完璧に実装してみせましたが、HTMLはdivの深い入れ子が幾重にも重なっていてアリスには到底理解できるものではありませんでした。
ボブに悪気があるわけでも、スキルが不足していたわけでもなく、HTMLで複雑なUIを作ろうとするとどうしても、機能やレイアウトの実現のために必要なHTML要素が大幅に増えてしまうのです。
GmailなどのWebアプリケーションのHTMLを調べてみても、相当に複雑です。
GmailのHTMLをChromeの開発者ツールで開いてみた状態。
HTMLとUIのためのコードはもう少し綺麗に分かれていてくれると嬉しくはないでしょうか。
すでにjQuery UIなどのフレームワークが、簡単なHTMLと少しのJavaScript実行コードだけでリッチなUIを実装できるようにしてくれていますが、結局、JavaScriptによって複雑なHTML構造は作られています。そしてその中身は外からも簡単にいじることができてしまいます。
そこへカプセル化の概念が登場すると、アリスはUIのために書かれた複雑なHTMLを開発者ツール上で目にすることはなくなります。一方、ボブもUI実装にあたってCSSやJavaScriptがアリスの担当するコード部分と干渉し合わない空間で、作業に専念することができます。
Shadow DOMはJavaScriptフレームワークでは決して実現できないカプセル化を、ブラウザの実装機能として提供してくれます。
まとめ
今回はShadow DOMの概念としての話で、内容が少しイメージしにくかったかもしれません。
実はShadow DOMの機能はすでに、部分的に体験することはできます。次回以降はサンプルコードを用いてShadow DOMが実際どんな挙動を示すのかを確かめてみたいと思います。