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
attributeStyleMap
とcomputedStyleMap()
attributeStyleMap
にCSSプロパティをsetして反映できる。
computedStyleMap()
はCSSで指定した値が色々と丸められた結果が入っている。例えばCSSでopacity
に9999
を指定していても、次の用に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の中で便利に使われるはず!大事!