CSS に関数と条件分岐が入ってきた:@function と if()
CSS に追加された @function と if() は、コンポーネントが抱える「同じ宣言のコピペ」を減らす。どちらもまだ Baseline ではないが、何を置き換えるのかは先に読む価値がある。
CSS に二つ新しいものが入った。関数を定義できることと、条件を書けること。どちらもまだ実験的だが、置き換える対象はどのプロジェクトにもある重複だ。
@function:実行時にカスタムプロパティを読める関数
@function --step(--n <number>: 1) returns <length> {
result: calc(var(--space-unit) * var(--n));
}
.card {
padding: --step(2);
}
形は @function --名前(--引数 <型>: 既定値) returns <型> { ... }、戻り値は result: に書き、呼び出しは --名前(実引数)。
SCSS の関数との違いは書き方ではなく評価されるタイミングだ。
| 評価 | var() を読めるか |
|
|---|---|---|
| SCSS 関数 | ビルド時 | いいえ(実行時の値は見えない) |
CSS @function |
計算値の段階 | はい |
この一行が価値のすべてだ。トークンがカスタムプロパティで、関数がそれを元に計算する場面では、プリプロセッサの関数は原理的に不可能 —— var(--space-unit) が何になるか知らないのだ。このサイトのテーマをトークン方式に移して以来、ずっと欲しかったものだ。
if():三つに分かれていた宣言を一つに
.card {
grid-template-columns: if(
media(width < 40rem): 1fr;
else: 14rem 1fr;
);
}
テストは三種類 —— style()(カスタムプロパティの値)、media()、supports()。else も複数分岐も書ける。
style() の形が最も役に立つ。
.badge {
color: if(
style(--skin: ink): var(--c-accent);
style(--skin: riso): var(--c-ink-2);
else: var(--c-text);
);
}
これまでは、同じセレクタを三つの [data-skin=...] ブロックにそれぞれ書くしかなかった。
現状:どちらも Baseline ではない
MDN の表示は両方同じで、限定的な利用、Baseline 未達、実験的。最新のブラウザでは動くが、古い端末は期待できない。
今使うなら段階的強化しかない。しかも順序が重要だ。
.card {
/* 先に古い書き方:if() を解釈できないブラウザはこちらを使う */
padding: 1rem;
padding: if(media(width > 60rem): 1.5rem; else: 1rem);
}
CSS が解釈できない値は宣言ごと破棄されるので、古いブラウザは静かに前の行に留まる。逆順に書くと逃げ道がなくなる。
私の判断
if() のほうが @function より価値が高い。
条件分岐はどのコンポーネントもぶつかる重複だ。ブレークポイント、スキン、明暗 —— 軸が増えるたびに層が増える。一方、関数の抽出が本当に効く場所は限られている。ほとんどの calc() の組み合わせは、関数にしても読みやすくならない。
もう一つ自制すべき点。CSS は純粋な宣言型から「宣言型 + 少しのプログラミング」へ動いているが、カスケード優先であることは変わらない。これで状態機械を作らないこと。if() で状態遷移を模し始めたら、そのロジックはそもそもスタイルシートに置くべきではなかった。

コメント
…