albatrosary's blog

UI/UXとエンタープライズシステム

Web標準だけでHTMLを部品化するWeb Componentsを試してみる

HTMLが部品化でき配布可能となればWeb開発に与える影響は大きなものとなります。AngularJSもこの流れの上にできてますので、魅力的なJavaScriptフレームワークです。部品化というのは完全独立なもので無くてはならないのでカスケードスタイルシートなどの影響も部品内で閉じていることが必要になります。

白石俊平がいたころ。: Web開発を革命する(かも知れない)Web Componentsという仕様について

を読んでWeb開発の革命(?)である「Web Components」が実際どうなるのかを味わってみた。Web Componentsの使用はAngularJSでも先行的に取り入れているとあるので興味深いところでもあります。

「Web Components」の技術要素としては

  • Custom Elements
  • HTML Templates
  • HTML Imports
  • Shadow DOM

です。Web Componentsを利用すると確かに近い未来のWeb開発がガラッと変わると思います。というか変わるでしょう。特にShadow DOMは「HTMLの部品化」に大きく貢献します。その流れを試験的に見ていきます(今回はChrome バージョン 36.0.1985.125 を使ってます。フラグの変更はしていません)。

Web Componentsのブラウザサポート状況は WebComponents.org の「BROWSER SUPPORT」という項目を見て頂けたらと思います。

 

Custom Elements

カスタムエレメントですが独自要素(タグ)を定義してしまおうというものです。詳細については

Custom Elements: HTML に新しい要素を定義する - HTML5 Rocks

を見て頂いた方が良いと思います。いくつかルールがあって「hoge-fuga」のように「-」が入らないといけないルールがあります。サンプルでそれを確認します。画面のハードコピーでは「document.registerElement」で要素が追加されているのが確認できます。命名規則にしたがっていない場合にはエラーが発生しています。

<!doctype html>
<html class="no-js">
<head>
<meta charset="utf-8">
<title>Web Components</title>
<link rel="shortcut icon" href="/favicon.ico">
</head>
<body>
<script>
var _name = ["x-component", "my-component", "my-component2", "x_component", "component"];
for (i = 0; i < _name.length; i++) {
try {
var component= document.registerElement(_name[i]);
document.body.appendChild(new component());
} catch(e) {
console.log(e);
}
}
</script>
</body>
</html>

f:id:albatrosary:20140723181206p:plain

HTML Templates

カスタムタグに自分で定義したtemplate要素をあてがいます。独自タグを定義しそこに部品化されたテンプレートをDOMに書き込みます。詳細については

HTML で利用可能になった Template タグ: クライアントサイドのテンプレートの標準化 - HTML5 Rocks

を読んでください。プログラムを実行した結果のハードコピーを添付します。独自タグx-componentにテンプレートが差し込まれているのが分かります。ただテンプレートで定義したカスケードスタイルシートが全体へ影響しています。このままではあまりメリットが感じられないかと思います。次にこのテンプレートを外だしにしていよいよ部品化の第一歩とします。

<!doctype html>
<html class="no-js">
<head>
<meta charset="utf-8">
<title>Web Components</title>
<link rel="shortcut icon" href="/favicon.ico">
<style>
div {
font-size: 10px;
}
</style>
</head>
<body>
<div>ここはtemplateの外</div>
<x-component></x-component>
<x-component></x-component>
<x-component></x-component>
<div>ここはtemplateの外</div>

<!-- テンプレート -->
<template>
<div>Template used</div>
<div>hoge</div>
<style>
div {
font-size: 20px;
}
</style>
</template>

<!-- アクティベート -->
<script>
// templateタグの取得
var templates = document.querySelector('template');
if(templates) {
var contents = templates.content;
// x-component
var xcomponents = document.querySelectorAll('x-component');
for (i = 0; i < xcomponents.length; i++) {
xcomponents[i].appendChild(contents.cloneNode(true));
}
} else {
console.log("templateタグが未定義かもね");
}
</script>
</body>
</html>

f:id:albatrosary:20140723181424p:plain

HTML Imports

テンプレートとして「components/x-components.html」に外だしにしました。これによりHTMLの部品化が出来ます。より複雑なHTMLを作成しそれを様々なプロジェクトに配布することも出来ると思います。しかし、カスケードスタイルシートが全画面に適用されています。良くある話ですが、あまりうまくないプロジェクトだとあるメンバーが作ったカスケードスタイルシートの影響で画面がボロボロにということもあったと思います。現状では、まだメリットが少ないように感じとれます。そこでShadow DOMを使います。こうすると適用される範囲がテンプレート内になりますので本格的に部品化がされます。 

詳しい説明はこちらを見てください

HTML Imports: ウェブのための #include - HTML5 Rocks

<template>
<div>Template used</div>
<div>hoge</div>
<style>
div {
font-size: 20px;
}
</style>
</template>

 

<!doctype html>
<html class="no-js">
<head>
<meta charset="utf-8">
<title>Web Components</title>
<link rel="shortcut icon" href="/favicon.ico">
<link rel="import" href="components/x-component.html">
<style>
div {
font-size: 10px;
}
</style>
</head>
<body>
<div>ここはtemplateの外</div>
<x-component></x-component>
<x-component></x-component>
<x-component></x-component>
<div>ここはtemplateの外</div>

<!-- アクティベート -->
<script>
<!-- http://www.html5rocks.com/ja/tutorials/webcomponents/template/ -->
var imports = document.querySelector('link[rel="import"]').import;
// templateタグの取得
var templates = imports.querySelector('template');
if(templates) {
var contents = templates.content;
// x-component
var xcomponents = document.querySelectorAll('x-component');
for (i = 0; i < xcomponents.length; i++) {
xcomponents[i].appendChild(contents.cloneNode(true));
}
} else {
console.log("templateタグが未定義かもね");
}
</script>
</body>
</html>

f:id:albatrosary:20140723181341p:plain

Shadow DOM

 Shadow DOMとしてImportしたHTMLをカスタムタグに設定しています。カスケードスタイルシートの範囲がテンプレート内に収まっているのが画面のハードコピーから分かります。また展開された部分が「#Shadow-root」となっているのもわかると思います。これで完全に部品化されました。

Shadow DOMの参考資料は Shadow DOM 101 - HTML5 Rocks です。

<!doctype html>
<html class="no-js">
<head>
<meta charset="utf-8">
<title>Web Components</title>
<link rel="shortcut icon" href="/favicon.ico">
<link rel="import" href="components/x-component.html">
<style>
div {
font-size: 10px;
}
</style>
</head>
<body>
<div>ここはtemplateの外</div>
<x-component></x-component>
<x-component></x-component>
<x-component></x-component>
<div>ここはtemplateの外</div>

<!-- アクティベート -->
<script>
<!-- http://www.html5rocks.com/ja/tutorials/webcomponents/template/ -->
var imports = document.querySelector('link[rel="import"]').import;
// templateタグの取得
var templates = imports.querySelector('template');
if(templates) {
var contents = templates.content;
// x-component
var xcomponents = document.querySelectorAll('x-component');
for (i = 0; i < xcomponents.length; i++) {
// ShadowDomを作成し注入
xcomponents[i].createShadowRoot().appendChild(contents.cloneNode(true));
}
} else {
console.log("templateタグが未定義かもね");
}
</script>
</body>
</html>

f:id:albatrosary:20140723181529p:plain

最後に

まだ限られたブラウザでしか実行することは出来ませんが、エンタープライズにとっては強力な技術要素になります。エンタープライズにとって部品化は魅力のあるキーワードの一つだからです。Web Componentsがうまく実装できるようになったら今ある色々なフレームワークはどうなるんだろ。