画面幅に合わせて文字や余白を滑らかに変えたいとき、以前は複数のメディアクエリを書く方法が一般的でした。CSSのclamp()を使えば、最小値・可変値・最大値を1行で指定できます。
ただし、3つの値を何となく並べるだけでは、途中でサイズが変化しなかったり、スマートフォンで文字が小さくなりすぎたりします。この記事では、clamp()の仕組み、値の決め方、実装例、よくある失敗、実務での応用まで解説します。
説明
clamp()とは
clamp()は、CSSの値を指定した範囲内に収めるための数学関数です。次の3つの値をカンマ区切りで指定します。
clamp(最小値, 推奨値, 最大値)
基本的な動作は次のとおりです。
- 推奨値が最小値より小さい場合:最小値を使用
- 推奨値が範囲内の場合:推奨値を使用
- 推奨値が最大値より大きい場合:最大値を使用
.title {
font-size: clamp(1.5rem, 4vw, 3rem);
}
この例では、文字サイズは4vwを基準に変化します。ただし、1.5remより小さくならず、3remより大きくなりません。
clamp()の計算ルール
clamp(MIN, VAL, MAX)は、考え方として次の式と同じです。
max(MIN, min(VAL, MAX))
最初に推奨値と最大値の小さい方を選び、その結果と最小値の大きい方を採用します。そのため、常に最小値から最大値までの範囲に収まります。
利用できる値
clamp()は文字サイズ専用ではありません。長さ、割合、数値、角度、時間など、そのCSSプロパティが受け取れる型に利用できます。
font-size:文字サイズwidth、max-width:要素の幅padding、margin、gap:余白grid-template-columns:Gridの列幅border-radius:角丸translate、rotate:変形量animation-duration:時間
引数ごとに異なる単位も利用できます。たとえば、最小値と最大値をrem、推奨値をvwにする指定は有効です。
min()・max()との違い
| 関数 | 役割 | 使用例 |
|---|---|---|
min() |
候補の中から小さい値を選ぶ | 幅の上限を設ける |
max() |
候補の中から大きい値を選ぶ | 幅や文字の下限を設ける |
clamp() |
最小値と最大値の両方を設ける | 範囲内で滑らかに変化させる |
.container {
/* 画面幅の90%を使うが、最大幅は1200px */
width: min(90%, 1200px);
}
.button {
/* 44pxより小さくしない */
min-height: max(44px, 3rem);
}
.heading {
/* 1.5remから3remの範囲で変化 */
font-size: clamp(1.5rem, 4vw, 3rem);
}
ブラウザ対応状況
clamp()は主要ブラウザで広く利用でき、MDNでは2020年7月以降、ブラウザをまたいで安定して利用できる機能として扱われています。2026年の通常のWeb制作では基本機能として採用できます。
ただし、古い端末のWebViewや長期間更新されていない業務端末を対象に含む場合は、案件ごとの対応ブラウザで確認してください。
実装例
1. 見出しの文字サイズを可変にする
h1 {
font-size: clamp(2rem, 1.2rem + 3vw, 4.5rem);
line-height: 1.15;
}
vwだけで指定すると、狭い画面で小さくなりすぎ、広い画面で大きくなりすぎます。rem + vwを推奨値にすると、基本サイズを保ちながら画面幅に応じて変化します。
2. 本文の文字サイズを調整する
body {
font-size: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
line-height: 1.8;
}
本文は見出しほど大きく変化させず、狭い範囲で調整します。最小値を読みやすいサイズに固定することが重要です。
3. セクションの上下余白を可変にする
.section {
padding-block: clamp(3rem, 8vw, 8rem);
}
モバイルでは余白を抑え、デスクトップではゆったりしたレイアウトにできます。複数のブレークポイントでpaddingを書き換える必要がありません。
4. コンテンツ左右の余白を可変にする
.page-inner {
padding-inline: clamp(1rem, 5vw, 5rem);
}
スマートフォンで最低限の余白を確保しながら、大画面ではコンテンツが画面端へ寄りすぎるのを防げます。
5. カード間のgapを可変にする
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
gap: clamp(1rem, 3vw, 2.5rem);
}
Gridの列数変化に合わせ、カード間の余白も自然に変化します。min(100%, 18rem)を使うことで、狭い画面で列幅が画面を超える問題も防げます。
6. カードの内側余白を可変にする
.card {
padding: clamp(1rem, 0.6rem + 2vw, 2rem);
}
同じカードコンポーネントをさまざまな画面幅で使う場合に有効です。
7. ボタンのサイズを調整する
.button {
min-height: 44px;
padding-block: clamp(0.75rem, 0.65rem + 0.3vw, 1rem);
padding-inline: clamp(1.25rem, 0.8rem + 2vw, 2.5rem);
font-size: clamp(0.95rem, 0.9rem + 0.2vw, 1.05rem);
}
タップ領域はmin-heightで確保し、見た目の余白と文字サイズだけをclamp()で調整します。
8. コンテンツ幅を制御する
.article {
width: clamp(20rem, 85vw, 60rem);
margin-inline: auto;
}
ただし、小さい端末では20remが画面幅を超える可能性があります。実務では次のようにmin()を組み合わせる方が安全です。
.article {
width: min(100% - 2rem, 60rem);
margin-inline: auto;
}
9. サイドバーの幅を可変にする
.layout {
display: grid;
grid-template-columns:
minmax(0, 1fr)
clamp(15rem, 22vw, 20rem);
gap: clamp(1.5rem, 4vw, 4rem);
}
メイン領域を柔軟に保ち、サイドバーだけに最小・最大幅を設定できます。
10. ヒーローエリアの高さを調整する
.hero {
min-height: clamp(28rem, 75svh, 52rem);
}
svhを使うと、モバイルブラウザのUIが表示されている状態の小さいビューポートを基準にできます。最低・最大の高さは固定値で制限します。
11. 画像サイズを可変にする
.avatar {
width: clamp(3rem, 8vw, 6rem);
aspect-ratio: 1;
object-fit: cover;
border-radius: 50%;
}
プロフィール画像やアイコンを画面幅に応じて変化させつつ、極端なサイズを防げます。
12. border-radiusを可変にする
.panel {
border-radius: clamp(0.5rem, 1.5vw, 1.25rem);
}
小さいコンポーネントでは控えめ、大きい画面では少し強めの角丸にできます。
13. positionのオフセットを調整する
.floating-action {
position: fixed;
right: clamp(1rem, 4vw, 3rem);
bottom: clamp(1rem, 4vw, 3rem);
}
固定ボタンを画面端から適切に離し、大画面で端に寄りすぎる状態を防ぎます。
14. CSS変数でデザイントークン化する
:root {
--space-fluid-sm: clamp(0.75rem, 0.5rem + 1vw, 1.25rem);
--space-fluid-md: clamp(1.5rem, 1rem + 2vw, 3rem);
--space-fluid-lg: clamp(3rem, 2rem + 5vw, 7rem);
}
.section {
padding-block: var(--space-fluid-lg);
}
.card {
padding: var(--space-fluid-md);
gap: var(--space-fluid-sm);
}
同じ計算式を各所へ直接書かず、CSS変数として管理するとデザイン全体の変化量を統一できます。
15. 画面幅から正確な可変式を作る
たとえば、画面幅375pxで文字サイズ24px、画面幅1440pxで56pxにしたい場合、推奨値は線形補間で求められます。
.hero-title {
font-size: clamp(
1.5rem,
0.796rem + 3.005vw,
3.5rem
);
}
計算の基本式は次のとおりです。
傾き = (最大サイズ - 最小サイズ)
÷ (最大画面幅 - 最小画面幅)
切片 = 最小サイズ - 傾き × 最小画面幅
ただし、デザイン上の数値を過度に厳密に合わせる必要がなければ、読みやすい値へ丸めた方が保守しやすくなります。
よくある失敗
最小値・推奨値・最大値の順序を間違える
/* 悪い例:最小値が最大値より大きい */
.title {
font-size: clamp(3rem, 5vw, 2rem);
}
基本は「最小値 ≤ 最大値」です。最小値が最大値を上回る指定では、期待した範囲制御になりません。
推奨値に固定値だけを使う
/* 範囲内では常に2remになり、可変にならない */
.title {
font-size: clamp(1rem, 2rem, 3rem);
}
画面幅に連動させたい場合、推奨値へvw、vi、cqiなどの相対単位を含めます。
vwだけで文字サイズを決める
/* 画面幅への依存が強すぎる */
.title {
font-size: clamp(1rem, 5vw, 5rem);
}
vwだけでは、ブラウザのズームやユーザーの文字設定を十分反映できない場合があります。文字サイズの推奨値にはremを足し、相対単位の影響を残します。
.title {
font-size: clamp(1.5rem, 1rem + 3vw, 4rem);
}
文字サイズの最大値を小さく制限する
MDNは、文字サイズにclamp()を使う場合、ズーム時に少なくとも200%まで拡大できるよう、最大値に相対単位を使い、最大値を最小値の2倍以上にする例を示しています。
/* 最小1rem、最大2rem */
.text {
font-size: clamp(1rem, 1rem + 1vw, 2rem);
}
実際のアクセシビリティは式だけで決まらないため、ブラウザを200%へズームして、文字が欠けないか、操作要素と重ならないかも確認します。
小さい画面で固定の最小幅がはみ出す
/* 320px未満の表示領域では横にはみ出す可能性がある */
.card {
width: clamp(320px, 50vw, 800px);
}
幅では、最小値そのものが表示領域を超えない設計が必要です。
.card {
width: min(100%, clamp(18rem, 50vw, 50rem));
}
どの基準で割合が計算されるか確認していない
vwはビューポート幅、%は多くの場合包含ブロック、cqiはクエリコンテナのインラインサイズを基準にします。同じ数値でも基準が異なるため、コンポーネント単位の変化にはvwが適さない場合があります。
すべてをclamp()で可変にする
チェックボックス、アイコンボタン、表の罫線など、安定した寸法が必要な要素まで可変にすると、レイアウトが落ち着かなくなります。変化させる値は、文字、余白、コンテンツ幅など効果が明確なものに限定します。
メディアクエリを完全に置き換えようとする
clamp()は値の連続的な変化に向いています。一方、1列から2列への変更、ナビゲーションの表示方式変更、要素の並び順変更など、構造的な切り替えにはメディアクエリやコンテナクエリが必要です。
応用
コンテナクエリ単位と組み合わせる
再利用可能なカードでは、画面全体ではなくカードを配置したコンテナの幅に合わせる方が自然です。
.card-area {
container-type: inline-size;
}
.card-title {
font-size: clamp(1.25rem, 1rem + 2cqi, 2rem);
}
1cqiはクエリコンテナのインラインサイズの1%です。同じカードをサイドバーとメイン領域へ配置しても、それぞれの領域に応じてサイズが変化します。
論理ビューポート単位viを使う
.title {
font-size: clamp(1.5rem, 1rem + 3vi, 4rem);
}
viはルート要素のインライン方向を基準にする単位です。横書きでは通常vwに近い動作をし、縦書きなどの書字方向も考慮できます。
CSS変数で最小値と最大値を変更する
.fluid-text {
--min-size: 1rem;
--max-size: 2rem;
font-size: clamp(
var(--min-size),
0.8rem + 1.5vw,
var(--max-size)
);
}
.fluid-text--large {
--min-size: 2rem;
--max-size: 4rem;
}
計算ロジックを共通化し、バリエーション側では上下限だけを変更できます。
min()やmax()を入れ子にする
.panel {
width: clamp(
min(20rem, 100%),
60vw,
70rem
);
}
最小値にmin(20rem, 100%)を使うことで、表示領域が20remより狭い場合にも横にはみ出しません。
calc()なしで数式を書く
現在のCSS数学関数では、引数内に加減乗除を直接記述できます。ただし、+と-の前後には空白が必要です。
.title {
font-size: clamp(1.5rem, 1rem + 3vw, 4rem);
}
calc(1rem + 3vw)と書いても問題ありません。チームのコーディング規約に合わせて統一してください。
@supportsで段階的に適用する
.title {
font-size: 2rem;
}
@supports (font-size: clamp(1rem, 2vw, 2rem)) {
.title {
font-size: clamp(2rem, 1.2rem + 3vw, 4.5rem);
}
}
古い組み込みブラウザを対象にする場合は、先に固定値を指定し、対応環境だけclamp()へ上書きします。
参考資料
- MDN Web Docs「clamp()」
- W3C CSS Values and Units Module Level 4
- web.dev「CSS min(), max(), and clamp()」
まとめ
clamp()は、最小値・推奨値・最大値を指定し、CSSの値を安全な範囲内で滑らかに変化させる関数です。
- 基本構文は
clamp(最小値, 推奨値, 最大値) - 推奨値には
rem + vwなど可変になる式を使う - 文字サイズだけでなく、余白、幅、gap、画像サイズにも使える
- 幅のはみ出し対策には
min()を組み合わせる - コンポーネント単位では
cqiとの組み合わせが有効 - 構造の切り替えはメディアクエリやコンテナクエリで行う
- 文字サイズはズームと200%拡大時の表示を確認する
最初は見出し、セクション余白、カードのgapなど、変化が分かりやすい箇所から導入すると扱いやすくなります。ブレークポイントの数を減らしながら、狭い画面から広い画面まで自然につながるレイアウトを作れます。
