ラベル Web Components の投稿を表示しています。 すべての投稿を表示
ラベル Web Components の投稿を表示しています。 すべての投稿を表示

2014年11月1日土曜日

Shadow DOM - Web Components を構成する技術

この記事は 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 についてより詳しく知りたいという方は、下記のドキュメントを参考にしてください。

2014年10月14日火曜日

Template - Web Components を構成する技術

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


先日 Web Components を構成する技術のひとつである Templates に関するビデオを公開しましたので、解説したいと思います。

なぜ今 Templates なのか

我々開発者にとってテンプレートを使うメリットは、デザイナーとの分業を容易にできる、という点にあります。

ウェブサイトを構築する際に利用されるテンプレートというと、以前は PHP や Python の Django, Ruby on Rails をはじめとするサーバー側での実装が主流でした。それがここ数年、ブラウザ側で処理するテンプレート技術が登場し、人気となってきています。

これは HTML5 などオープンウェブ技術の発展により、全体的なアーキテクチャが変わりつつあるためです。サーバーはコンピューターがデータを処理するもの、クライアント側はユーザーがデータを加工するもの、といった分担がより進んでおり、サーバー側で完結していた MVC (Model, View, Controller) がクライアント側とまたがり、より明確な役割を担うべく変遷をしている時期である、と言えるかもしれません。

それに伴い、クライアント側でも MVC のような構成が必要だという機運が高まり、ここ最近は特に AngularJS や Backbone.js, Ember.js といったフレームワークがよく使われるようになってきました。テンプレートを活用できるフレームを利用することで、HTML や CSS といった見た目を担当するデザイナーが、命令的手法 (imparative) より比較的容易な宣言的手法 (declarative) のみに集中してプログラムを記述することでき、チームとしての生産性の向上が期待できます。

ブラウザ側のテンプレートエンジンといえば Mustache.js, Handlebar.js, AngularJS, Backbone.js など、JavaScript で実現するものが人気を博していますが、こういったソリューションにはいくつか解決すべき課題もあります。

div タグを使ったアプローチ

div タグを display:none; として表示されないようにしたものにテンプレートを埋め込み、表示する際にコピーして利用します。このアプローチでは、まだ利用されていない画像などのリソースでもサーバーに取りに行ってしまうため、パフォーマンスが犠牲になるという欠点があります。
<div style="display:none;">
  <div>
    <h1>Web Components</h1>
    <img src="http://webcomponents.org/img/logo.svg">
  </div>
</div>

script タグを使ったアプローチ

script タグに type="text/javascript" 以外の属性を付与してテンプレートを埋め込み、表示する際にコピーして利用します。このアプローチでは、.innerHTML を使う必要があるため、セキュリティ上のリスクが伴うという欠点があります。
<script type="text/template">
  <div>
    <h1>Web Components</h1>
    <img src="http://webcomponents.org/img/logo.svg">
  </div>
</script>
そこで登場したのが、<template> 要素です。
<template> は Web Components の一翼を担うウェブ標準候補技術で、「自律的に処理されない HTML」をドキュメントに埋め込むことができます。

「自律的に処理されない HTML」とは、下記のような特徴を持ったものです。
  • script タグが含まれても、実際に利用されるまでスクリプトを実行しない
  • imgvideo といったリソースが含まれても、実際に利用されるまでサーバーにリソースを取りに行かない

Templates の使い方

テンプレートを宣言するには、利用したいテンプレートの HTML を <template> タグで囲んでください。実際に利用するには、JavaScript を使う必要があります。

HTML
<template id="template">
  <style>
    ...
  </style>
  <div id="container">
    <img src="http://webcomponents.org/img/logo.svg">
  </div>
</template>

JavaScript
<script>
  var template = document.querySelector('#template');
  var clone = document.importNode(template.content, true);
  var host = document.querySelector('#host');
  host.appendChild(clone);
</script>
<div id="host"></div>

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

クエリーした template ノードは document.importNode() を使ってクローンします。2 つめの引数に true を指定することで再帰的にノードの中身もクローンされます。これを別のノードに appendChild() して、はじめて template に命が吹き込まれます。つまり
  • テンプレートに script タグがある場合、append されてから実行される
  • テンプレートに画像などのリソースがある場合、append されてから読み込みが始まる
  • テンプレートに style タグがある場合、append されてから有効になる

注意

ひとつ注意点があります。既存のテンプレートエンジンを使われたことのある方や、既に Polymer をすでにいじっている方であれば、どうやって

プレースホルダーを使って変数を埋め込む
<template bind="{{items}}"></template>

繰り返しを表現する
<template repeat="{{item in items}}"></template>

条件分岐をする
<template if="{{item.active}}"></template>

と思われるかもしれません。しかしこれはデータバインディングといって、テンプレートとは区別される別の機能です。そういった機能を自分で実装することなくテンプレートで利用したい場合は、Polymer (TemplateBinding) や x-tags といったフレームワークを利用することをおすすめします。

ブラウザサポート状況

<template> 要素は 2014 年 10 月現在 Chrome, Opera, Safari, Firefox でサポートされています。サポート対象としたいブラウザで利用可能かどうか知りたい場合は、chromestatus.com をご覧下さい。Internet Explorer のような未対応ブラウザで <template> 要素を利用するには platform.js という Polyfill があります。

まとめ

いかがでしたでしょうか?Templates は主に Web Components の概念を実現することを視野に考えられた仕様ではありますが、それ以外の利用法もありそうです。ぜひ Templates を活用して、素敵な Web Components を作ってみてください。また、何かユニークな活用法があれば、教えて下さい。

Templates についてより詳しく知りたいという方は、下記のドキュメントが参考になると思います。

2014年5月19日月曜日

なぜ Web Components はウェブ開発に革命を起こすのか



ウェブアプリケーションのフロントエンドに関わる方なら、もう Web Components という言葉を全く聴いたことがない方は少ないのではないでしょか。
すでに関連記事も数多く出回っており、実際に触り始めている方も多いと思います。しかし、なぜこれが革命的技術なのか、周囲の人に簡潔に説明できる方はどれくらいいるでしょうか?この記事では、それを試みていきたいと思います。

デジタル部品の流通革命

ソフトウェア部品の流通に今、大きな変化が起きてきています。

数年前のオープンソース環境を覚えているでしょうか?レポジトリは集中管理型の subversion、リリースは zip、テストは手動。Issue の登録もプロジェクトごとにことなるバグ管理システムが使われていたため、とっつきづらかったでしょうし、パッチを送るのも面倒でした。

そんなオープンソースを取り巻く環境が、git や GitHub の登場を皮切りに、目覚ましく発展しています。ネットワークレポジトリの環境が整い、CI (Continuous Integration) によるテストやデプロイの自動化、必要な時に最新のソースコードを手軽にダウンロードできるパッケージマネージャーの充実など、すべてが楽に、しかもスピードを早めてきています。ソフトウェア部品の開発から再利用までのサイクルが分単位まで短縮されることで、コミュニティを介したフィードバックやコントリビュート (Patch / Pull Request) も活性化し、品質を高めていくための仕組みも今までになく効率化しています。オープンソースは、ついに真のエコシステムを手に入れつつあると入っても過言ではないでしょう。

この動きは、フロントエンド開発においても大いに役立てられています。特に grunt, npm, bower 等との組み合わせは、だいぶ浸透してきたのではないでしょうか?

UI コンポーネントのエコシステム

これまでに最も大きな成功を収めたフロントエンド向けソフトウェアに jQuery があります。DOM 操作だけでなく、簡単に複雑な UI を実現できる jQuery UI のようなプラグインを活用している開発者の方は多いと思います。カレンダーのUI (Datepicker) や、タブインターフェース、ダイアログといった、素の HTML が苦手とするユーザーインターフェースを実装する敷居を大きく下げてくれたのも、jQuery UI でした。



もちろん、その対抗馬となる UI ライブラリもたくさん登場しています。Kendo UI, ExtJS, Dojo, Bootstrap など、数え上げればキリがありません。しかしひとつ言えるのは、それぞれに独自の思想や作法があるということです。そのため、実際に使うには、API よりも、まずは思想と作法を学ぶところからスタートしなければなりません。
また、選択肢が多いということは、人それぞれに得意なライブラリや好みが別れてしまうため、プロジェクトでひとつを選択する必要に迫られた場合、誰かが妥協したり、新たな学習コストがかかってしまうことも、忘れてはいけません。

Web Components

それでは、UI ライブラリが同じ思想、作法で使えるようになるとしたらどうでしょうか?別に言い方をするなら、「UI コンポーネントの思想と作法が標準化されるとしたら」。

その答えが、 Web Components です。Web Components には以下のような特徴があります。
  • ウェブ標準になる予定
  • 既存の HTML / CSS / JavaScript の知識の延長で使える
  • UI コンポーネントを HTML タグとして作ることができる
  • コンポーネントはカプセル化されるため、外部を汚染しない
  • 再利用が可能
  • 分業がしやすい
理屈で説明されるより、実際に動くものを見たほうが話は早いでしょう。簡単な例をご紹介します。



画像をクリックすると実際に動作するデモを見ることができます。このデモのソースコードはこちら
この見た目にかっこいいノブ類ですが、Web Components (Polymer) で作られています。
ドラッグして上下に動かすことで、パラメータを増減。Shift キーを押しながらドラッグすれば、1 ずつ動かすことができます。そして、変更したパラメータは value に設定されます。
<webaudio-knob diameter="64" max="100" sprites="100" src="img/LittlePhatty.png" step="1" style="left: 128px; position: absolute; top: 76px;" tooltip="Knob2 tooltip" value="50"></webaudio-knob>
何よりも、ソースを見てみると、これらの要素には、<webaudio-knob> というタグが使われていることに気付くと思います。ノブの見た目や値の範囲は、ネイティブな HTML 要素のお作法に則り、属性を使って変更することができます。

注目していただきたいのは、head タグ内にある
<link href="webcomponents/webaudio-controls.html" rel="import"></link>
の部分です。この一行が、<webaudio-knob> の利用を可能にしています (実際には Polyfill の platform.js も読み込んでいます)。JavaScript 一切なしで、HTML タグだけでこれが実現できるとしたら、お手軽だと思いませんか?

Web Components が主流になれば、ユーザーは UI コンポーネントを、思想や作法を気にせず、ネイティブの DOM 要素と同様に扱うことができるのです。

もう少し具体例が見たい

分かりやすい一例としては、Twitter Button なんていかがでしょうか?<twitter-button></twitter-button> として、必要な情報は属性として与えれば、Twitter ボタンを表示することができます。Twitter ボタンを実装したことがある方であれば、これがいかに楽な作業かわかると思います。



また、customelements.io というサイトでは、これも含めて、公開されている Web Components でできた UI コンポーネントを探すことができます。

うってつけのビデオもあります。先日 Google で開催された All About Polymer というイベントで Rob Dodson が Google Map を使ったアプリのライブコーディングを披露しました。ほとんどタグを追加するだけで派手なアプリが作り上げられていく様は圧巻です。ちなみに英語ですが字幕付きですので、英語の勉強も兼ねて、ぜひ見てみて下さい。


Web Components の構成要素

少し技術的な解説をします。Web Components は、大きく 4 つのテクノロジーで構成されています。
  • Custom Elements
  • HTML Imports
  • Template
  • Shadow DOM
各テクノロジーについて、簡単に説明してみましょう。

Custom Elements

独自タグをブラウザに認識させます。
このタグはプロパティやメソッド、イベントを持つことができるため、ネイティブな DOM 要素と同様な使い勝手を実現することができます。
上記 <webaudio-knob></webaudio-knob> の例で言えば
var knob = document.querySelectorAll('webaudio-knob')[0];
knob.setValue(100);
とすることで、JavaScript から 命令的 (declarative - 宣言的 の反対である imperative 的) に、value を変更することができます。
knob.value = 100;
とすることもできます。

実は Custom Elements は GitHub で既に使われてたりします。


DevTools で見てみると
  • time タグを拡張 (is="relative-time") して、タグ中に表示される時間を相対的にしている
  • title-format 属性を使って、ツールチップ表示の日時にフォーマットを指定している
なんて使い方をしているようです。

未対応ブラウザ向けには、Polymer の Custom Elements の Polyfill使っているようです。なんか見てたらホレボレしてきました。

Template

標準のテンプレート機能を提供します。
template のコンセプトは長らく検討されてきました。最近では Handlebar.js や Backbone.js (Underscore), AngularJS のテンプレートが人気ですが、それのウェブ標準版と思って下さい。既存のハックと比べると
  • どこに置いても template 内は DOM と認識されないので、それだけでは中の script を実行したり、画像を取りに行ったりといったことが起きない
  • 取り込む際は文字列ではなく DOM として認識できるので、扱いやすい
など、できそうでできなかった機能が提供されています。なお、プレースホルダーやバインディングの機能はこれ自体提供していない点に注意してください。

HTML Imports

ひとつのタグで複数のリソースを読み込むことができます。
jQuery UI にしろ Bootstrap にしろ、JavaScript、CSS などを、それぞれ別々に取り込む必要がありました。import タグを使えば、これひとつで UI コンポーネントと、それに必要なリソースを取り込むことができるようになります。

Shadow DOM

カプセル化した HTML 要素を追加できます。
パッと見の効果は、見えないマークアップを追加できることですが、もっと大きな役割はカプセル化できることです。UI ライブラリでありがちな落とし穴は
  • 同じクラス名を使って意図しない要素にスタイルが当てられてしまう
  • 別の要素に当てたスタイルが意図しない箇所に影響を与えてしまう
ですが、Shadow DOM は外の世界と中の世界を分断することで、カプセル化を可能にします。

ブラウザベンダーのスタンス

標準化を目指していると言いましたが、ブラウザベンダーの足並みが揃わなければ標準化することはできません。しかし、各ブラウザベンダーは、いずれも Web Components に注目し、実装と仕様策定を同時並行で進めています。

Google

Google は Web Components で最も大きな役割を担っています。仕様作成者はいずれも Google エンジニアで、Google Chrome では既にほとんどの機能を実装しており、バージョン 36 では HTML Imports も取り込まれ、すべての機能が about:flags のフラグ無しで動く状態になる見込みです。
また、まだアルファ版ではありますが、Web Components をベースにした Polymer というフレームワークを開発しており、完成すれば、その上で様々なコンポーネントを動かせるよう準備を進めています。同時に、Polymer の開発に当たり、Web Components 未対応ブラウザでの動作が行えるよう platform.js という Polyfill (JavaScript で機能をエミュレートするライブラリ) の開発も進められています。

Mozilla

Google の次に積極的に Web Components に取り組んでいるのは、間違いなく Mozilla です。x-tag というフレームワークを開発しており、UI コンポーネント集 Brick も公開されています。

Apple

Blink が WebKit から fork された時点で Shadow DOM が削除されるなど、一時は Web Components への対応に否定的と見られましたが、先日別ブランチ上で開発を進めることが発表され、様子を伺いつつも興味を示しています。

Microsoft

Microsoft の Web Components 対応は、status.modern.ie を見る限り、いずれの機能も Under Consideration の状態ですが、HTML Templates の仕様に関わるなど、興味を示しています。

ユースケース

どのような場面で Web Components を使うことができるでしょうか?いくつか例を挙げてみます。

プロダクト専用の UI コンポーネントを作る

サービスを開発するに当たり、UI のコンポーネント化を想定して設計します。そうすることで、UI コンポーネントを作るチームは、その機能に集中することができますし、使うチームは、想定通りにインターフェースが使える前提で開発を進めることができます。分業が楽になるのも Web Components の利点のひとつです。

複数サービスで共有の UI コンポーネントを作る

ポータルサイトや、複数のサービスが統合されたサイトを運営している企業の場合、テーマや UI を統一したいケースが多いと思います。それこそ Web Components が威力を発揮するチャンスです。共通サーバーから CSS や画像を配信するインフラは既に整っているところが多いでしょうから、それを Web Components のものに差し替えることで実現できるでしょう。

公開されている UI コンポーネントを使う

ちょっとしたサービスを個人で作りたい場合、開発者がデザインまで手がけるのはなかなか大変です。Bootstrap のように、お手軽にできあいのデザインで UI が組めるのはありがたいですが、Web Components を使えば、もう少し複雑なことも比較的簡単に実現できます。公開されている Web Components のライブラリを customelements.io などで探し、再利用することで、開発の工数を大幅に減らすことができるようになるでしょう。まだまだ数は少ないですが、Web Components が広まれば、むしろ自分が必要なものを探す方が大変になるかもしれません。

どこで学べばいいのか

ここまで読んで、ぜひ Web Components を使いたい!と思った方は、どこで使い方を学べばいいのでしょう?仕様を読んで下さい…というと大変ですよね。仕様は仕様なので、使い方が書いてあるわけではありません。幸いなことに、HTML5Rocks にはすでにたくさんの記事が上がっています。これらの記事はメンテされていますので、最新の仕様 (実装) に則っていると思って大丈夫です。

でも HTML5Rocks の記事は英語だから読むのが大変・・・そんな方のために、日本語訳しておきました。

その他日本語資料

質問はどこに?

日本語なら、html5j のメーリングリストで聞けば、誰かしら答えてくれると思います。英語であれば、StackOverflow で polymer タグを使うと良いと思います。

まとめ

僕なら、誰かに Web Components は何がそんなに素晴らしいのか?と聞かれたら、こう答えます:

Web Components はウェブの UI コンポーネントを標準化し、エコシステムに乗ることで、開発効率を飛躍的に向上する技術 だからであると。

みなさんが素敵な UI コンポーネントを公開してくださるのを楽しみにしています。