CSSのHoudiniとは何者か

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の変数に型や初期値、また継承の可否を設定することで堅牢にします。

````js
CSS.registerProperty({
  name: "--sample-color", // 変数名
  syntax: "<color>", // 型
  inherits: false, // 継承の可否
  initialValue: "black" // 初期値
});
````

この場合、`--sample-color`変数の値に`color`型以外の値が入れられたら`initialValue`の値が適用されます。

### CSS Typed OM
例えば以下の様にJavaScriptでスタイルを操作したとき、CSSエンジンは文字列で渡された値を解析し、数値に変換しているのでオーバーヘッドが大きくなります。

```js
document.querySelector('div').style.width = 100 + 'px';
```
Typed OMは**プロパティの値に対応した型付きのオブジェクト**を渡すことでこの処理を効率よく、そして容易に行うための仕組みです。

Chrome Canaryでは「試験運用版のウェブ プラットフォームの機能」を有効にすることでTyped OMが試せます。

````js
var element = document.querySelector('div');
element.styleMap.set('width', new CSSSimpleLength(100, 'px'));
console.log(element.styleMap.get('width'));
````

実行するとコンソールには下記の様に表示されます。

````js
CSSSimpleLength {value: 100, type: "px", cssText: "100px"}
````

この`CSSSimpleLength`が値に対応した型で他にも`CSSNumberValue`や`CSSKeywordValue`などの型があります。

### CSS Layout API
親要素内の子要素に対し独自のレイアウトを定義できるようになります。定義したレイアウトは`display`プロパティで使えるので`flexbox`に未対応なブラウザに向けて`Polyfill`を実装するといったことも可能です。

````js
registerLayout('my-layout', class {...});
````

````css
.my-element {
  display: layout('my-layout');
}
````

`registerLayout`の第一引数にレイアウト名、第二引数にはレイアウトの計算を行うクラスを渡します。そして`layout`関数で`display`プロパティに適用します。

### CSS Painting API
`canvas`のようなAPIを使って独自の`background-image`を作ることができます。Painting APIもChrome Canaryで試すことができます。

````js
registerPaint('circle', class {...});
````

````css
.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](https://www.w3.org/community/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の是非の判断はまだ難しいですが、いずれにしても、今後の展開を見守ってみようと思います。








## 参考
+ [W3C CSS-TAG Houdini Editor Drafts](https://drafts.css-houdini.org/)
+ [WICG/CSS-Parser-API](https://github.com/wicg/css-parser-api/)
+ [Houdini – CSS の秘密を解き明かすもの](https://developers.google.com/web/updates/2016/05/houdini?hl=ja)
+ [Houdini: Maybe The Most Exciting Development In CSS You’ve Never Heard Of](https://www.smashingmagazine.com/2016/03/houdini-maybe-the-most-exciting-development-in-css-youve-never-heard-of/)
+ [CSS Houdini / CSS Working Groupミーティングに参加しました](http://vivliostyle.com/ja/blog/2015/02/sydney/)