PostCSSプラグイン: to-longhand

Edge 17にあるカスタム・プロパティーとショートハンド・プロパティーでのバグが、パッチ・レベルでは直りそうもない。つまり、そう簡単には世界から消えてくれないことが確定してしまったため、しばらく(最低1年半くらい)の間ロングハンド・プロパティーで書かなくてはならない。しかし、そう書き直されたCSSを見ていると、とにかく悲しいので、to-longhandというPostCSSプラグインを書いて誤魔化すことにした。

marginpaddingプロパティーの変換は簡単だ。まず4値の指定に変換し、それから上右下左に割り当てるだけだ。

borderプロパティー群のショートハンドの変換は難しい。歴史的に幅、スタイル、色の順で書かれることが多いようだし、僕もそう書いているので、それで決め打ちということにした。


ヒマがあったら順不同に対応できるように書き直したい、と考えていたが、どうやら無理そうだ。どのような値が指定されているのかざっと調べれば良いと単純にとらえていたが、問題になるのはカスタム・プロパティーなので、ランタイム、すなわちブラウザーでレンダリングされるまで値がどのようなものか確定しない。

:root {
  --foo: double;
  --bar: 3px;
}

.test {
  border: var(--foo) var(--bar);
}

恣意的なコードを出すと、こういうborderプロパティーがありうる。--fooを辿るとdouble、同じように--barを辿ると3pxなので、このプロパティーからは以下のようなロングハンド・プロパティー群が生成できるだろう。

.test {
  border-style: var(--foo);
  border-width: var(--bar);
}

一見、これで良さそうだが、カスタム・プロパティーなので、その値がいつも同じタイプであるとは限らない。別のルールセット内で上書き定義されることもあるからだ。

.test2 {
  --foo: #f0f;
}

トリッキーに書くなら、このようにして色とスタイルを同時に変更できる。この場合、生成したborder-styleプロパティーで色を指定することになってしまうので、無視される。

「このCSSがおかしい」というのは確かだろう。しかし、カスタム・プロパティーは汎用的なものなので、思っても見ない形でこういったケースに遭遇する可能性が高い。ロングハンド・プロパティーへの展開を汎用的に作ることはあきらめ、ショートハンド・プロパティーの書き方に(意見の一致が見られそうな)制限をかける方が無難だろう。


変数(的な何か)がある、すなわち型が必要という話であるのかもしれない。TypeScript+CSSOMで書くみたいな未来もありえそうだ。