ようやくmin()
やmax()
、clamp()
関数が、安定して使えるように揃った。で、いろいろ試していたんだけど、値に<length-percentage>
を要求するプロパティーで使う時、その中で0を使うことができなくてハマった。なので0px
や、短くしたいなら0%
や0Q
と書かないといけない。calc()
関数での制限と同じ。
具体的には以下のように書くと動かない。よくmargin-left: 0
と書くのでハマりやすそう。
.test {
margin-left: clamp(
0,
(100vw - 37rem - 1em) / 2,
5vw
);
}
これらの関数のカンマで区切られた値は、それぞれ数式として処理される。そのため、calc()
関数と同じように、0
は計算結果として0
を返すので、<integer>を受け入れるプロパティーにのみしか使えない。仕様でも「Additionally, math functions that resolve to <number> can be used in any place that only accepts <integer>.」と触れられている。margin-left
プロパティーの値は<length-percentage> | auto
なので、3行目の0
でエラーになってしまう。
0%
と書けば、問題なく動く。calc(0 - 20rem)
などと、0
から引いて負の値を作ろうとしてエラーになるのと似ているけど、ちょっと違う。こっちは両辺の型が一致していないので、計算式として成立しないというエラー。
上記例のclamp()
関数は、幅37rem
の要素をほぼセンタリングしつつ、大きい画面では5vw
の余白で左に寄せようというもの。普通、センタリングするにはauto
キーワードを使えばいいけど、clamp()
関数内ではauto
キーワードが使えないので、計算しなきゃならない。5行目の最大値だけでなく、3行目の最低値が必要なのは、描画領域の幅が37rem
以下だった場合に、負の値になってしまうから。
こういうものは、通常、メディア・クエリーでやる。この場合は多分こう書くだろう。
.test {
margin-left: auto;
}
@media (min-width: 41.111em) {
.test {
margin-left: 5vw;
}
}
37rem
をセンタリングした時に、左の余白が5vw
以上にならないようにしたいので、37 / 0.9 = 41.111
がメディア・クエリーのmin-width
で指定する値になる。これで期待通りに動作する。
この例ではclamp()
関数で書いた方が短くなっているので、CSSの軽量化にもつながる……と言いたいところだけど、ならない。サポート状況の前後を考慮すると、だいたいclamp()
関数内でカスタム・プロパティーを使うだろうと考えられる、かなり長くなる。
スコープ化できるカスタム・プロパティーを利用できるため、引数の解釈が初期状態で固定されるメディア・クエリーよりも、柔軟に対応できる。対して、calc()
関数と同じように単位付きの値から単位なしの値を計算できないので、やれることにも限界がある。いろいろな知識を増やしたうえで、どう使うのが正しいのか、どうメディア・クエリーと使い分けるのか、これらの関数にしかできないことは何かなどを見極めなければならない。
その前に、最小値を設定したいならmax()
関数で、最大値を設定したいならmin()
関数だという、max-width
プロパティーと逆なことをおぼえないといけない。間違えまくった。
min()
やmax()
関数は、引数がひとつだけの場合(min(1.618 * 1rem)
とか)、calc()
と等価になる。CSSの最小化ツールにcalc()
をmin()
に置き換える機能があっても良さそう。数年後くらいには。