WEBフロントエンドの開発は常にブラウザと共にあります。しかしながら各ブラウザ間の実装の違いにより手を焼かせられることは日常茶飯事。特にCSSにはJavaScriptのようにPolyfillを提供出来る手段がないので、新しく便利なプロパティが登場してもブラウザの実装を待つ必要がありました。
「あのCSSプロパティ使いたいけど、あのブラウザには実装されてないしな...。」
そんな悩みを将来はHoudiniで解決できるかもしれません。
Houdiniについては名前だけは知ってる程度だったので、丁度良い機会と思い調べてみました。
Houdiniとは?
機能の標準化には長い年月が必要です。JavaScriptであれば開発者自身の手でグローバルオブジェクトやPrototypeを拡張するなどしてその機能を再現することが出来ましたがCSSでは不可能でした。
そこでブラウザのレンダリングプロセスの中でJavaScriptがアクセスできる範囲を広げ(APIの提供)、CSSの機能を拡張出来るようにしようというのがHoudiniです。Houdini Task Force(一部APIはWICG)にて仕様策定が進められており将来的にはW3Cの標準化を目指しています。2016年12月21日現在、全てのAPIがドラフト段階です。
HoudiniのAPI
- Properties and Values API
- CSS Parser API
- CSS Typed OM
- CSS Layout API
- CSS Painting API
- Font Metrics API
以下に紹介するAPIの内容はドラフトやその他公開されている情報を元に自分なりの解釈を交えて書いてますので誤解もあるかもしれません。最終的にはやはりドラフトを読んでいただくのが良いと思います。
Properties and Values API
CSSの変数に型や初期値、また継承の可否を設定することで堅牢にします。
CSS.registerProperty({
name: "--sample-color", // 変数名
syntax: "<color>", // 型
inherits: false, // 継承の可否
initialValue: "black" // 初期値
});
この場合、--sample-color
変数の値にcolor
型以外の値が入れられたらinitialValue
の値が適用されます。
CSS Typed OM
例えば以下の様にJavaScriptでスタイルを操作したとき、CSSエンジンは文字列で渡された値を解析し、数値に変換しているのでオーバーヘッドが大きくなります。
document.querySelector('div').style.width = 100 + 'px';
Typed OMはプロパティの値に対応した型付きのオブジェクトを渡すことでこの処理を効率よく、そして容易に行うための仕組みです。
Chrome Canaryでは「試験運用版のウェブ プラットフォームの機能」を有効にすることでTyped OMが試せます。
var element = document.querySelector('div');
element.styleMap.set('width', new CSSSimpleLength(100, 'px'));
console.log(element.styleMap.get('width'));
実行するとコンソールには下記の様に表示されます。
CSSSimpleLength {value: 100, type: "px", cssText: "100px"}
このCSSSimpleLength
が値に対応した型で他にもCSSNumberValue
やCSSKeywordValue
などの型があります。
CSS Layout API
親要素内の子要素に対し独自のレイアウトを定義できるようになります。定義したレイアウトはdisplay
プロパティで使えるのでflexbox
に未対応なブラウザに向けてPolyfill
を実装するといったことも可能です。
registerLayout('my-layout', class {...});
.my-element {
display: layout('my-layout');
}
registerLayout
の第一引数にレイアウト名、第二引数にはレイアウトの計算を行うクラスを渡します。そしてlayout
関数でdisplay
プロパティに適用します。
CSS Painting API
canvas
のようなAPIを使って独自のbackground-image
を作ることができます。Painting APIもChrome Canaryで試すことができます。
registerPaint('circle', class {...});
.my-element {
--circle-color: blue; /* registerPaintに渡したクラス内からアクセスできる */
background-image: paint('circle');
}
GoogleChromeのgithubではPainting APIを使ってMaterial designのようなリップル効果を実装した例が公開されています。
https://github.com/GoogleChrome/houdini-samples/tree/master/paint-worklet/ripple
動作の様子はYoutube上で公開されています。
https://www.youtube.com/watch?v=BX_qv2yKSUk
CSS Parser API
このAPIの仕様はHoudini Task ForceではなくWICGが進めています。いまいちよく理解できていないのですが、CSS Parser APIはレンダリングプロセスのParserにアクセスし、CSSの構文を拡張するためのAPIのようです。
Font Metrics API
Font Metrics API はテキストのバウンディングボックスのサイズを取得できるAPIです。高度な文字組みを再現する場合などに有効だそうです。
Workletについて
WorkletはLayout APIやCSS Painting APIで実装したスクリプトを読み込み、それぞれのレンダリングプロセスで動作させます。また実装したスクリプトがメインスレッドを圧迫しないよう、独立したスレッドで動作することでパフォーマンスを担保しようとします。
まとめ
ドラフト段階なので本当に実現するかまだ分かりませんが、実現すればgithub上でCSSのPolyfillが公開されプロジェクトに取り入れる、なんてことが当たり前の世界になるかもしれません。
ただ使い方を誤れば拡張されすぎてカオスになったCSSを相手に四苦八苦するなんてことも容易に想像できまし、そうなてしまっては本末転倒です。
Houdiniの是非の判断はまだ難しいですが、いずれにしても、今後の展開を見守ってみようと思います。