clamp() の役割
clamp(MIN, PREFERRED, MAX) は 3 つの値を受け取り、真ん中の値がほかの 2 つの間にある限り、それを返します。定番の使い方は、画面に合わせて大きくなりつつ、適切な限界で止まる見出しで、メディアクエリは要りません:
推奨値は 1rem + 3vw、つまり 16px に幅の 3% を足したものです。幅 800px のプレビューでは 16 + 24 = 40px で、24px (1.5rem) と 48px (3rem) の間にあるので、見出しは 40px になります。320px のスマートフォンでは推奨値は 25.6px です。1067px を超えると 48px を超えるので、48px で止まります。ウィンドウのサイズを変えて、数値が変わるのを見てください。ここでの vw は、プレビューのフレームの幅に対するパーセントです。
ウィンドウのサイズを変えずに見る
vw はビューポートに従うので、読みながら変えるのは簡単ではありません。コンテナクエリの単位は、代わりにコンテナに従います。cqi はコンテナの幅の 1% です。スライダーをドラッグしてボックスを変えると、同じ種類の clamp() が反応します:
一番左までスライドすると、タイトルは 20px (MIN) で止まります。一番右までスライドすると 40px (MAX) で止まります。その間は 0.5rem + 6cqi に従います。vw の例と同じしくみで、ものさしが小さいだけです。
3 つの引数
font-size: clamp(1rem, 0.8rem + 1vw, 1.5rem);
/* MIN PREFERRED MAX */
| 引数 | 役割 | よく使う単位 |
|---|---|---|
| MIN | 値の最小 | rem |
| PREFERRED | 画面に合わせて変わる値 | rem + vw (または cqi) |
| MAX | 値の最大 | rem |
各引数の中では、calc() を書かなくても計算ができます。1rem + 2vw はそのままで大丈夫です。+ と - の前後には空白が必要で、ないと宣言全体が無効になります。
MIN が MAX より大きいと MIN が勝ちます。clamp(3rem, 5vw, 2rem) は常に 3rem です。
真ん中の値を計算する
320px の画面で 16px、1280px の画面で 24px になるようにフォントを大きくするには:
- 傾き: (24 − 16) ÷ (1280 − 320) = 8 ÷ 960 = 0.00833。これは 0.833vw です (vw は 100px あたり)。
- 出発点: 16px − 0.00833 × 320px = 13.33px。これは 0.833rem です。
- その周りに限界を置きます:
font-size: clamp(1rem, 0.833rem + 0.833vw, 1.5rem);
幅 320px では 13.33 + 2.67 = 16px、1280px では 13.33 + 10.67 = 24px になり、その範囲の外では限界の値にとどまります。オンラインの「clamp 計算ツール」がしているのは、まさにこの計算です。
min() と max()
clamp() は、もっと単純な 2 つの関数の組み合わせです:
min(a, b)は 小さいほう の値を返すので、上限を決めます。max(a, b)は 大きいほう の値を返すので、下限を決めます。clamp(MIN, VAL, MAX)はmax(MIN, min(VAL, MAX))と同じです。
名前は最初は逆に感じます。「最大 600px」と言いたいときに使うのは min() です。
幅の広いプレビューでは、1 つ目のカードは 420px で止まります。260px の親の中では 100% のほうが小さいので、2 つ目のカードは 260px です。max(12px, 3%) は、1 つ目のカードには親 (body) の幅の 3% (800px のプレビューで約 23.5px) を与え、2 つ目には 12px を与えます。260px の 3% (7.8px) が下限より小さいからです。
width: min(100%, 420px) は、以前の width: 100%; max-width: 420px; の組み合わせを 1 つの宣言で置き換えます。
フォントサイズ以外: 余白と幅
clamp() は長さを受け取るどのプロパティでも使えます。真ん中の値にパーセントを使うと、ビューポートではなく親に対してコンポーネントがなめらかに変わります:
300px の親の中では、カードは幅 240px (80%) で padding は 15px (300px の 5%) です。760px の親の中では 80% が 608px になるので、カードは最大値の 520px で止まり、760px の 5% は 38px なので、padding は 32px で止まります。
アクセシビリティ: 真ん中の値に rem を残す
font-size: 5vw のように vw だけで作ったフォントサイズは、読者がブラウザの設定で標準のフォントサイズを大きくしても大きくなりません。ズームすると CSS ピクセルで見たビューポートが狭くなるので、ブラウザのズームでも大きくなりません。rem の部分 (1rem + 2vw) と rem の限界を加えると、文字が読者の設定に結び付いたままになります。rem と vw については 単位のページ で詳しく解説しています。
よくある間違い
- 最小値に
min()を使う。min()は小さいほうの値を選ぶので、上限になります。「少なくとも 12px」ならmax(12px, ...)を使いましょう。 +や-の前後に空白がない。clamp(1rem, 1rem+2vw, 3rem)は無効で、プロパティは前の値に戻ります。- 真ん中が
vwだけ。 文字が読者のフォントサイズの設定を無視します。remの項を足しましょう。 - MIN が MAX より大きい。 結果は常に MIN になり、意図とはたいてい違います。
- フォントサイズの限界を
pxで書く。 大きい文字が必要な読者でも文字が制限されてしまいます。remを使いましょう。
よくある質問
CSS の clamp() は何をしますか?
clamp(MIN, PREFERRED, MAX) は、推奨値が 2 つの限界の間にある間はそれを使い、外れると近いほうの限界を使います。font-size: clamp(1rem, 4vw, 2rem) はビューポートの幅の 4% に従いますが、1rem より小さく、2rem より大きくはなりません。
clamp でレスポンシブなフォントサイズを作るには?
真ん中にビューポートを基準にした値、両側に固定の限界を置きます。真ん中に rem を混ぜると、文字が読者のフォントサイズの設定にも従います: font-size: clamp(1.5rem, 1rem + 2vw, 3rem);。
clamp() で最小値が最大値より大きいとどうなりますか?
最小値が勝ちます。clamp() は最大値の後に最小値を適用するので、clamp(3rem, 5vw, 2rem) は常に 3rem になります。
CSS の min() と max() の違いは何ですか?
min() は値の中で一番小さいものを返すので、上限として働きます: width: min(100%, 600px) は 600px より広くなりません。max() は一番大きいものを返すので、下限として働きます: font-size: max(1rem, 2vw) は 1rem より小さくなりません。
clamp() はすべてのブラウザで使えますか?
使えます。clamp()、min()、max() は現在の Chrome、Edge、Firefox、Safari のすべてで動き、長さ、数値、パーセント、角度を受け取るどのプロパティにも使えます。