clamp()関数における最小値と最大値の競合

使われるプロパティーや式の書き方によって、clamp()関数の最小値が最大値を上回ってしまう場合がある。そのように競合した場合は、必ず最小値が勝つ。min-widthmax-widthプロパティーが競合した場合と似た挙動になる。

この挙動について、CSS Values and Units Module Level 4仕様の安定版(20190131)では微妙な表現になっている。clamp(MIN, VAL, MAX)max(MIN, min(VAL, MAX))と等価だとしか書いていない。最終的にmax(MIN, MAX)が評価されるということにはなるので、最小値が優先されそうだと理解できるだろう。

編集版仕様では、「favoring the min calculation if it conflicts with the max」(最小計算値が最大計算値と競合した場合は最小計算値を支持する)と、明確に書かれるようになった。いずれにしても最小値が優先される。


ともあれ競合する例(デスクトップ・ブラウザーのみで動作する)を考えてみよう。これは、画像の幅を40remにしたいが、最小でも500pxは確保しつつ、はみ出さないように最大で100%に制限したいとするものだ。競合する簡単な例を他にうまく思いつかなかった。

.test {
	width: clamp(
		500px,
		40rem,
		100%
	);
}

描画領域の幅がおよそ530px以上の場合は、40remか最大値が選択される。また、フォント・サイズを下げ、40rem500pxを下回った場合は、最小値が選択される。ここまでは要件通りの挙動だが、描画領域の幅がおよそ500px以下の場合、最小値が優先されてはみ出してしまうことがわかる。はみ出したくないという要件が、最小値を優先する仕様によって満たせていない。

最大値を優先したい場合は、min()関数を入れ子にする。最小値が優先される挙動を変更したいので、最小値で入れ子にしなければならない。

.test {
	width: clamp(
		min(
			500px,
			100%
		),
		40rem,
		100%
	);
}

最大値がうまく反映されない場合は、この挙動を疑ってみるといいかもしれない。clamp()の性質上、min-widthmax-widthプロパティーの競合より発生しやすいので、遭遇する可能性はそれなりにあると思う。