HoudiniのCSS Typed OMとは

CSSの魔法使いになれると噂のHoudiniだけれども、先日リリースされたChrome 66でCSS Typed OMが使えるということだったので使ってみた。

Houdiniの全体像についてはこちらが詳しい。
https://qiita.com/mizukazu/items/46eaebcdb87407d83557

仕様

https://www.w3.org/TR/css-typed-om-1/
まだWorking Draft。

何ができるの?

JavaScriptでCSSの単位付き数値をオブジェクトで扱うことができるようになる。
今まではCSSで指定する数値(pxや%とか)というのは、JavaScriptにおいては文字列で扱っていたと思う。
文字列だと計算はできない。なので数値で計算しておいてから、文字列として単位を付けるという手段を取った。

const widthNum = 100
const nextWidthNum = widthNum * 2
el.style.width = nextWidthNum + 'px'

でもCSS Typed OMを使えばその面倒は無くなる。なぜならオブジェクトとして単位を持っており、計算もできるから。
Typed OMを使うと、100pxを2倍して要素に設定するコードは次のようになる。

const width = CSS.px(100)
const nextWidth = width.mul(2)
el.attributeStyleMap.set('width', nextWidth)

便利か?

先の例だと単純すぎて、「Typed OMなんて使わず、文字列でpx付与したほうが簡単でいいじゃん」と思ったかもしれない。
じゃあ、calcの式を組み立てる場合はどうだろう?
transformで大量の指定がある場合は?
そういった複雑なことはTyped OMだと良いかもしれない。

calcの組み立て

CSSのcalc関数では、単位の違う値を計算できるので便利に使える。
でもこの式をJavaScriptの数値と文字列を駆使して組み立てるのは大変。
でもTyped OMなら簡単にできる。calc(100% - 10px)を組み立てたい場合は次のようになる。

const calc = CSS.percent(100).sub(CSS.px(10))

calc.toString()
// => "calc(100% + -10px)"

もっと複雑にして、calc(100% - (10px + 10vh))なんてのも(どんな式だよ・・)次のように書ける。

const calc = CSS.percent(100).sub(CSS.px(10).add(CSS.vh(10)))

calc.toString()
// => "calc(100% - (10px + 10vh))"

.toString()は確認のために実行しているだけなので、実際に要素に反映する場合は先の例のようにattributeStyleMap.setすれば良い。

transformの指定

transformの指定も文字列だけでやると大変な部分。何かしらのプラグインに頼りたくなる。
でも、Typed OMのCSSTransformValueを使えばプラグインに頼る必要はない。
例えばtranslate3d(1px, 2px, 3px) rotate(45deg)を組み立てる場合は次のようになる。

const translate = new CSSTranslate(CSS.px(1),CSS.px(2),CSS.px(3))
const rotate = new CSSRotate(CSS.deg(45))
const transform = new CSSTransformValue([translate, rotate])

transform.toString()
// => "translate3d(1px, 2px, 3px) rotate(45deg)"

基本的な使い方

基本を抜きに例を出しすぎたので、基本的なことも書いておく。

単位付きの値 CSSUnitValue

CSSオブジェクトがpxだとかpercentだとかnumber(ただの数字)だとかを持っている。次のように定義する。

const px = CSS.px(3)
console.log(px)
// => CSSUnitValue {value: 3, unit: "px"}

const percent = CSS.percent(100)
console.log(percent)
// => CSSUnitValue {value: 100, unit: "percent"}

CSSNumericValue.parseを使えば、文字列のパースもできる。

CSSNumericValue.parse("100px")
// => CSSUnitValue {value: 100, unit: "px"}

// calcなんかもパース可能
CSSNumericValue.parse("calc(100% - 10px)")
// => CSSMathSum

attributeStyleMapcomputedStyleMap()

attributeStyleMapにCSSプロパティをsetして反映できる。
computedStyleMap()はCSSで指定した値が色々と丸められた結果が入っている。例えばCSSでopacity9999を指定していても、次の用にcomputedStyleMapを使用して値を取得した場合は1になる。

el.attributeStyleMap.set('opacity', CSS.number(9999))

el.attributeStyleMap.get('opacity')
// => CSSUnitValue {value: 9999, unit: "number"}

el.computedStyleMap().get('opacity')
// => CSSUnitValue {value: 1, unit: "number"}

計算

CSSUnitValueには計算系の関数が用意されている。
ざっくりといえば計算を行った時、単位が同じであればCSSUnitValueのままで計算してくれて、単位が違う場合はcalcを使った方法にしてくれる。つよい。

終わりに

まだ最新chromeでしか使えないわけだけど、いつか駆使する時代が来るだろうか。
Typed OMはHoudiniの中でも地味というか、ただ単位を良い感じに扱えるというだけだけど、他のHoudiniのWorkletの中で便利に使われるはず!大事!

タイトルとURLをコピーしました