こんにちは、aggre です。

最近はマイクロフロントエンドなどの文脈で、Web Components や、その要素技術である Custom Elements などの話題をよく聞くようになりました。

マイクロフロントエンドの文脈においては Web Components の実装そのものは React や Vue でもよいことになっています。実装を隠ぺいして境界をクリーンにするのが Web Components なので、マイクロフロントエンドは相性のよい活用です。

しかしせっかく Web Components を採用するなら、その実装の選択肢に 標準仕様の Web Components もあることを知っておくといいと思います。

標準仕様の Web Components でも React や Vue を代替することができるようになっていることを理解すると、組み合わせて使うときの解像度も変わるはずです。

Web Components は標準仕様なので、全部を置き換えるのではなく、使えるところで使えばいいんです。

そこで今回は、Web Components の開発の基礎を振り返ってみます。サンプルコードはすべて jsfiddle に書いたので、Result タブを開いたりソースを書き換えたりしていろいろ試すことができます。

詳しい話は、11月25日に開催される HTML5 Conference 2018 の僕のセッションでお話しする予定です。ぜひお越しください。

Web Components のサポート状況

これまで、まともにサポートしているブラウザは Chrome だけでした。それはもう昔の話です。2018 年も終盤の今、Web Components のサポート状況はかなり改善されました。

Firefox Platform Status  によるサポート状況をまとめました。

Custom Elements のサポート状況
Shadow DOM のサポート状況
ES( JavaScript ) Modules のサポート状況

上記 3 つの仕様は Web Components 構成する主な仕様です。いずれも Chrome, Safari, Firefox においてはサポート済みです。

Edge だけ Custom Elements と Shadow DOM が 開発中 ステータスになっていますが、以前は長らく 検討中 だったことを考えると大きな進歩です。

Internet Explorer が…

IE はもう積極的な DOM のアップデートを行わないので、Web Components には対応していません。

非対応ブラウザ向けには webcomponents.js というポリフィルがあります。一応ポリフィルで大抵のことはできるのですが、技術的に限界があるのでけっこうケアは必要です。

その IE ですが、国内では Windows 7 にバンドルされている IE11 が最大のシェアをもっているはずです。Windows 7 の IE11 は 2020年1月15日 にサポート期限を迎えますから、それまでのあいだ、IE11 ユーザーをターゲットに含んだプロダクトには Web Components は使えないと考えたほうが無難です。もしくは IE11 をサポート対象外として割り切ったほうがプロダクトの品質を上げるケースもあると思います。

Windows 8.1 は OS 自体が普及しなかったので、特殊な事情がない限り無視できるのではないでしょうか。Windows 10 からはデフォルトが Edge なので気にしません。

モバイルは production-ready になった

iOS や Android のブラウザは Web Components をサポートしています。つまり、モバイル向けのプロダクトなら本番で積極的に使えます!

もしモバイル向けではなくても、IE11 on Windows 7 が 2020年1月 にサポートを終えた後にリリースするプロダクトなら、今から Web Components を前提として開発できます。

Web Components の基礎

Web Components はいくつかの仕様の総称です。実際には、

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

といった仕様に細分化されます。しかしこの仕様群はちょっと古くて、HTML Imports は非推奨になりました。JavaScript/TypeScript からテンプレートを操作するのが当然の環境になっていることを考えると、HTML Templates も積極的に使う動機が弱いと思ってます。

現時点のフロントエンド環境を踏まえると現実的には、

  • Custom Elements
  • Shadow DOM
  • ES Modules

などがフォーカスすべき仕様になってきます。特に重要なのが Custom Elements と Shadow DOM です。

Custom Elements

Custom Elements は、独自のエレメントを定義する仕様で、Web Components の中でもとりわけ重要な役割を担っています。

Custom Elements では HTMLElement クラスを継承することで、独自のエレメントを定義します。以下はシンプルな例です。

window.customElements.define というメソッドがあるので、要素名とクラスを渡すことで Custom Elements が作られます。

connectedCallback というメソッドが出てきますが、これは標準で定義されているコールバックです。React のクラスのようにいくつかのコールバックが用意されています。次にすべて挙げます。

  • constructor
  • connectedCallback
  • disconnectedCallback
  • attributeChangedCallback
  • adoptedCallback

このほか、observedAttributes というゲッターによって Custom Elements を制御します。

ライフスタイルのタイミング

それぞれのライフスタイルコールバックがいつ呼ばれるのかを確認してみます。adoptedCallback はあまり使わないので、このあとで試します。

createElement や setAttribute などの DOM 操作時にそれぞれのコールバックが呼ばれていることが分かるかと思います。

次に adoptedCallback を試すために、事前に次のようなページを作っておきます。

さっきのサンプルコードとほぼ同じですが、x-app 要素の削除がなくなったことと、HTML 上に初めから <x-app></x-app> が存在しています。(仕様を簡単に試せるようにするために変えています)

このページを iframe として読み込むページを作り、次のように操作してみます。

結果として、x-app 要素は iframe の内側の DOM から、外側の DOM に移動します。

もともとの document から別の document へと移動し、x-app 要素の ownerDocument が変更されたタイミングで adoptedCallback が呼び出されています。あまり使うことが多いコールバックとは言えないでしょう。

コールバックの使い分け

constructor は初期状態の定義など、connectedCallback はテンプレートの最初の描画など、attributeChangedCallback はテンプレートの更新など、disconnectedCallback は状態の削除など、といった使い分けが自然かと思います。

Shadow DOM

Shadow DOM はカプセル化された DOM を定義する仕様で、Custom Elements と合わせて使われることが多いです。

カプセル化することによって、CSS の競合を防いだり、複雑な DOM ツリーを隠してシンプルな一要素として見せることができます。

特にフロントエンド開発者にとって嬉しいのは CSS の競合を防ぐ という点です。セレクターが衝突することをまったく意識する必要がないので、シンプルなセレクターでスタイルを指定できます。

Shadow DOM と Custom Elements は単独で使うこともできますが、合わせて使うことが一般的です。

Shadow DOM を作るときは、Element.attachShadow({mode: 'open'}) を実行します。次のサンプルは、親要素の CSS が Shadow DOM 内に適用されていないことを試しています。

Custom Elements の中で使うときは this が Element なので、this.attachShadow({mode: 'open'}) と書きます。

mode

引数として {mode: 'open'} を渡していましたが、このオプションは 基本的に open を使うべき だと覚えるのが楽です。

ほかに {mode:'close'} を使うこともできます。違いは、Shadow DOM の外側から JavaScript によるアクセスを許可するかどうかです。

close モードはブラウザによるビルトインの要素で使われています。フロントエンド開発者が自分で Custom Elements を作るときにおいては、JavaScript  によるアクセスを拒否すると不便なことのほうが多いので、基本的には open モードを使います。

Shadow DOM のスタイリング

Shadow DOM の内側はカプセル化されているのでシンプルなセレクターを使うことができます。

また、外部ファイルを @import して使うこともできます。この場合にも Shadow DOM の境界を越えることはありません。次は簡単な例です。

ご覧の通り、Shadow DOM の内部では特殊なセレクターが使えます。

:host というセレクターは Shadow DOM の親要素自体を指します。ここでは x-app 要素です。

:host であまり多くのスタイリングをしてしまうと柔軟性を損なうので、具体的なスタイリングは子要素に寄せていくほうがいいでしょう。

将来的には CSS Shadow Parts などの仕様も使えるようになり、Shadow DOM のスタイリングがより便利になっていくはずです。

CSS Shadow Parts


実用的な開発や Web Components の使いどころ

実際に Web Components を使った開発をするときの 現時点における現実的な方法論 や、Web Components をどのように使うのがよいか、などを HTML5 Conference 2018 でお話する予定です。

参加費無料で、有益なセッションがたくさんあります。

お会いできるのを楽しみにしています!


License
Photo: Spooky, Flying Space-Cat by Gail S

FRAME00 の CTO です。TypeScript をよく書いてます。Web Components, lit-html などフロントエンドスタック、Lambda や Dynamo, S3 などのサーバーレススタックが好きです。あとアニメをよく見ます。