



WithCodeMedia-1-pc
WithCodeMedia-2-pc
WithCodeMedia-3-pc
WithCodeMedia-4-pc




WithCodeMedia-1-sp
WithCodeMedia-2-sp
WithCodeMedia-3-sp
WithCodeMedia-4-sp









生徒画面幅ごとに文字サイズを変えたくて、メディアクエリが5個くらいに増えてしまいました…。
ペン博士それclamp()なら1行で済むよ。最小・推奨・最大の3つを渡すだけ。今日は計算の考え方と、見出し・本文・余白まで使える値をまとめて渡すね。
見出しはPCで48px、スマホで28px。この調整をメディアクエリで書くと、ブレイクポイントの数だけ指定が増えていきます。しかも境界で文字サイズがカクッと飛ぶのが避けられません。
clamp()を使えば、画面幅に応じてなめらかに変化する文字サイズを1行で書けます。しかも下限と上限を自分で決められるので、小さくなりすぎる・大きくなりすぎるという事故も起きません。
この記事では、3つの引数の意味から、実務で使える計算方法、見出し・本文・余白への適用、アクセシビリティ上の注意点まで解説します。コピペで使える値の一覧も用意しました。

書き方は単純です。カンマ区切りで3つの値を渡します。
/* clamp(最小値, 推奨値, 最大値) */
h1 {
font-size: clamp(1.75rem, 5vw, 3rem);
}| 位置 | 役割 | この例では |
|---|---|---|
| 第1引数 | これ以上小さくしない下限 | 1.75rem(28px) |
| 第2引数 | 画面幅に応じて変わる推奨値 | 5vw |
| 第3引数 | これ以上大きくしない上限 | 3rem(48px) |
動きはこうです。画面が狭いときは5vwが小さくなるので下限の28pxで止まる。広いときは5vwが大きくなるので上限の48pxで止まる。その中間だけが可変になります。
つまり「小さい画面でも読める大きさは確保しつつ、大画面で巨大化もしない」という制御が1行で書けます。

可変にするだけならfont-size: 5vwでも動きます。しかし実用に耐えません。
/* 悪い例:下限も上限もない */
h1 {
font-size: 5vw;
}
/* 320pxのスマホ → 16px(見出しなのに本文と同じ)
1920pxのモニタ → 96px(画面を埋め尽くす) */さらに深刻なのが拡大表示への影響です。vwは画面幅だけで決まるため、利用者がブラウザの文字サイズを大きくしてもまったく変化しません。
clamp()の下限・上限にremを使えば、拡大設定が効く範囲を残せます。これが実務でclamp()を選ぶ最大の理由です。

第2引数は勘で決めても動きますが、狙った画面幅で狙ったサイズにしたいときは計算します。2点を通る直線を求めるだけです。
/* 375px→28px、1200px→48px をなめらかにつなぐ */
h1 {
font-size: clamp(1.75rem, 1.18rem + 2.42vw, 3rem);
}第2引数がrem + vwの形になっているのがポイントです。remの部分が拡大設定に反応するため、vw単独より安全になります。
毎回計算するのが面倒なら、次の早見表の値をそのまま使ってください。よく使う範囲は網羅しています。
| 用途 | clamp()の値 | 375px→1200pxでの変化 |
|---|---|---|
| 特大見出し | clamp(2rem, 1.2rem + 3.4vw, 3.5rem) | 32px → 56px |
| h1 | clamp(1.75rem, 1.18rem + 2.42vw, 3rem) | 28px → 48px |
| h2 | clamp(1.4rem, 1.09rem + 1.33vw, 2rem) | 22px → 32px |
| h3 | clamp(1.15rem, 1rem + 0.6vw, 1.5rem) | 18px → 24px |
| 本文 | clamp(1rem, 0.95rem + 0.2vw, 1.125rem) | 16px → 18px |
| 注釈 | clamp(0.8rem, 0.77rem + 0.12vw, 0.875rem) | 13px → 14px |
clamp()は文字サイズ専用ではありません。数値を取るプロパティならどこでも使えます。
/* 余白:狭い画面で詰まりすぎない */
.section {
padding-block: clamp(2.5rem, 1.5rem + 4vw, 6rem);
}
/* 記事の横幅:小さい画面では全幅、大画面では読みやすい幅で止める */
.container {
width: clamp(320px, 92vw, 760px);
margin-inline: auto;
}
/* 要素同士の間隔 */
.cards {
gap: clamp(1rem, 0.5rem + 2vw, 2rem);
}
/* 角丸やボーダーにも使える */
.hero {
border-radius: clamp(8px, 1.5vw, 24px);
}特に効果が大きいのはセクションの上下余白です。PCで十分な余白を取ると、スマホでは間延びします。clamp()にしておけば、両方で適切な間隔になります。
本文の文字サイズにも使えますが、見出しほど大胆に変えてはいけません。
/* 良い例:変化幅は2px程度に留める */
body {
font-size: clamp(1rem, 0.95rem + 0.2vw, 1.125rem);
line-height: 1.8;
}
/* 悪い例:本文が画面幅で大きく動く */
body {
font-size: clamp(0.875rem, 3vw, 1.5rem); /* 読みにくい */
}本文は16〜18pxの範囲で十分です。読者は文字サイズの変化に敏感で、大きく動くと落ち着いて読めません。可変にするのは見出しと余白、と割り切るのが実務的です。
行間も合わせて調整すると質が上がります。文字が大きくなるほど行間の倍率は下げるのが定石です。
h1 {
font-size: clamp(1.75rem, 1.18rem + 2.42vw, 3rem);
line-height: 1.25; /* 大きい文字は詰め気味に */
}
p {
font-size: clamp(1rem, 0.95rem + 0.2vw, 1.125rem);
line-height: 1.8; /* 本文はゆったり */
}clamp()があればメディアクエリが不要になるわけではありません。役割が違います。
| やりたいこと | 適した方法 | 理由 |
|---|---|---|
| 文字サイズを滑らかに変える | clamp() | 境界で飛ばない |
| 余白を画面幅に合わせる | clamp() | 1行で書ける |
| 1カラム↔2カラムの切替 | メディアクエリ | レイアウトは段階的に変わる |
| 要素の表示・非表示 | メディアクエリ | 連続値では表せない |
| フォント自体を変える | メディアクエリ | 値ではなく種類の切替 |
目安は連続的に変わるものはclamp()、段階的に切り替わるものはメディアクエリです。この線引きで書くと、CSSの見通しが良くなります。
同じ系統の関数が3つあります。clamp()は残り2つの組み合わせです。
/* min():候補のうち小さいほうを採用=上限を設ける */
.box { width: min(90vw, 800px); }
/* max():候補のうち大きいほうを採用=下限を設ける */
.title { font-size: max(1.25rem, 3vw); }
/* clamp(a, b, c) は max(a, min(b, c)) と同じ意味 */
.title { font-size: clamp(1.25rem, 3vw, 2.5rem); }上限だけ、下限だけで足りる場面ではmin()やmax()のほうが読みやすくなります。両方必要になったらclamp()にする、という順で考えます。
見落とされがちですが、アクセシビリティ上の重要な論点です。ブラウザの文字サイズ変更で本文が拡大できないサイトは、読めない人が出ます。
rem + vwの形にする/* 拡大設定が効く書き方 */
h1 { font-size: clamp(1.75rem, 1.18rem + 2.42vw, 3rem); }
/* 効かない書き方(避ける) */
h1 { font-size: clamp(28px, 5vw, 48px); }pxで固定した場合、ブラウザの文字サイズ設定を変えても見た目が1ミリも変わりません。remで書くだけで対応できるので、初期段階からremに統一しておくのが安全です。

プロジェクト全体で使うなら、変数にまとめておくと管理が一箇所で済みます。
:root {
--fs-xs: clamp(0.8rem, 0.77rem + 0.12vw, 0.875rem);
--fs-base: clamp(1rem, 0.95rem + 0.2vw, 1.125rem);
--fs-lg: clamp(1.15rem, 1rem + 0.6vw, 1.5rem);
--fs-xl: clamp(1.4rem, 1.09rem + 1.33vw, 2rem);
--fs-2xl: clamp(1.75rem, 1.18rem + 2.42vw, 3rem);
--space-sm: clamp(0.75rem, 0.6rem + 0.6vw, 1.25rem);
--space-md: clamp(1.5rem, 1.1rem + 1.6vw, 3rem);
--space-lg: clamp(2.5rem, 1.5rem + 4vw, 6rem);
}
h1 { font-size: var(--fs-2xl); }
h2 { font-size: var(--fs-xl); }
h3 { font-size: var(--fs-lg); }
body { font-size: var(--fs-base); }
.section { padding-block: var(--space-lg); }この6行を用意しておけば、以降はサイズを直接書かずに済みます。デザインの調整も変数の値を変えるだけで全体に反映されます。
clamp()が思ったように動かない場合、原因はほぼ次の5つです。
| 症状 | 原因 | 対処 |
|---|---|---|
| まったく効かない | 引数が2つ以下 | 3つ渡す(min/maxと混同) |
| 常に最小値になる | 推奨値が小さすぎる | vwの係数を上げる |
| 常に最大値になる | 推奨値が大きすぎる | vwの係数を下げる |
| 文字拡大に反応しない | px指定になっている | remに置き換える |
| 横スクロールが出る | 幅にvwを使った | %やmin()にする |
最後の項目は見落としやすいポイントです。100vwはスクロールバーの幅を含むため、幅の指定に使うと横スクロールが発生します。幅には%を使ってください。
コピペしてそのまま使える一式です。375px〜1200pxの範囲でなめらかに変化します。
:root {
/* 文字サイズ */
--fs-note: clamp(0.8rem, 0.77rem + 0.12vw, 0.875rem);
--fs-body: clamp(1rem, 0.95rem + 0.2vw, 1.125rem);
--fs-h3: clamp(1.15rem, 1rem + 0.6vw, 1.5rem);
--fs-h2: clamp(1.4rem, 1.09rem + 1.33vw, 2rem);
--fs-h1: clamp(1.75rem, 1.18rem + 2.42vw, 3rem);
--fs-hero: clamp(2rem, 1.2rem + 3.4vw, 3.5rem);
/* 余白 */
--sp-xs: clamp(0.5rem, 0.45rem + 0.2vw, 0.75rem);
--sp-sm: clamp(0.75rem, 0.6rem + 0.6vw, 1.25rem);
--sp-md: clamp(1.5rem, 1.1rem + 1.6vw, 3rem);
--sp-lg: clamp(2.5rem, 1.5rem + 4vw, 6rem);
}
body {
font-size: var(--fs-body);
line-height: 1.8;
}
h1 { font-size: var(--fs-h1); line-height: 1.25; }
h2 { font-size: var(--fs-h2); line-height: 1.35; }
h3 { font-size: var(--fs-h3); line-height: 1.45; }
.section { padding-block: var(--sp-lg); }
.container { width: min(92%, 760px); margin-inline: auto; }
.stack > * + * { margin-top: var(--sp-md); }これだけでメディアクエリを1つも書かずに、文字サイズと余白のレスポンシブ対応が完了します。レイアウトの切り替えが必要になった時点で、初めてメディアクエリを足してください。
実際のパーツで、メディアクエリ版とclamp()版を比べます。行数と保守性の差が分かります。
/* メディアクエリ版:4段階でも境界で飛ぶ */
.hero__title { font-size: 1.75rem; }
@media (min-width: 480px) { .hero__title { font-size: 2.25rem; } }
@media (min-width: 768px) { .hero__title { font-size: 2.75rem; } }
@media (min-width: 1024px) { .hero__title { font-size: 3.25rem; } }
@media (min-width: 1280px) { .hero__title { font-size: 3.5rem; } }
/* clamp()版:1行、しかも境界が無い */
.hero__title { font-size: clamp(1.75rem, 1.2rem + 3.4vw, 3.5rem); }13行が1行になり、さらに479pxと480pxの間で文字が飛ぶ現象も消えます。ブレイクポイントを増やすほど差が開きます。
/* メディアクエリ版 */
.section { padding-block: 2.5rem; }
@media (min-width: 768px) { .section { padding-block: 4rem; } }
@media (min-width: 1200px) { .section { padding-block: 6rem; } }
/* clamp()版 */
.section { padding-block: clamp(2.5rem, 1.5rem + 4vw, 6rem); }余白は文字サイズ以上に段階が目立ちます。スクロール中に急に間隔が変わると、レイアウトが崩れたように見えることがあります。
.card {
padding: clamp(1rem, 0.7rem + 1.2vw, 2rem);
border-radius: clamp(10px, 0.6vw + 8px, 16px);
gap: clamp(0.75rem, 0.5rem + 1vw, 1.5rem);
}小さな画面では余白を詰めて情報量を確保し、大きな画面ではゆったり見せる。カード内部の3つの値を同時に可変にすると、密度が自然に変わります。
clamp()は画面幅を基準にします。一方、カードのように置き場所によって幅が変わる部品では、親要素の幅を基準にしたいことがあります。
/* 親をコンテナとして登録する */
.card-area {
container-type: inline-size;
}
/* 親の幅に応じて可変にする(cqi=コンテナ幅の1%) */
.card__title {
font-size: clamp(1rem, 0.85rem + 2cqi, 1.5rem);
}vwをcqiに置き換えるだけで、画面幅ではなく親要素の幅に反応するようになります。サイドバーとメインで同じカードを使い回す場合に効果的です。
| 単位 | 基準 | 使う場面 |
|---|---|---|
vw | 画面の幅 | ページ全体の見出し・余白 |
cqi | コンテナの幅 | どこにでも置く部品 |
% | 親要素の幅 | レイアウトの幅指定 |
rem | ルートの文字サイズ | 拡大設定に追従させたい値 |
すべてclamp()の中で混ぜて使えます。基準をどこに置くかだけ意識してください。
既存サイトに入れる場合は、影響範囲の小さい順に進めるのが安全です。
:rootにサイズと余白の変数を置く/* 確認用:現在の計算値をDevToolsで見る
要素を選択 → Computed → font-size の値が
画面幅を変えるたびに滑らかに変わればOK */検証は375px・768px・1200px・1920pxの4点で行えば十分です。下限と上限で止まっているか、中間でなめらかに変わっているかを見ます。
clamp()は書けるようになってからのほうが、判断を誤りやすい関数です。現場で見かける失敗を3つ挙げます。
文字も余白もボーダーも角丸も可変にすると、画面幅を変えたときに全部が同時に動いて落ち着かない見た目になります。可変にするのは見出し・セクション余白・コンテナ幅の3つで十分です。ボーダー幅やアイコンサイズは固定のほうが安定して見えます。
/* 悪い例:3倍以上動く */
h2 { font-size: clamp(1rem, 6vw, 3.5rem); }
/* 良い例:1.4〜1.6倍に収める */
h2 { font-size: clamp(1.4rem, 1.09rem + 1.33vw, 2rem); }最小と最大の比は1.4〜1.8倍が扱いやすい範囲です。それ以上開くと、中間の画面幅で意図しないサイズになります。デザインカンプが2種類(スマホ・PC)しかないなら、その2点を結ぶ値に収めてください。
h1とh2で係数が違うと、特定の画面幅でh2のほうが大きくなることがあります。変数で管理していれば起きにくいですが、個別に書いていると発生します。
/* 検証:320px〜1920pxで階層が保たれるか確認する
h1: clamp(1.75rem, 1.18rem + 2.42vw, 3rem)
h2: clamp(1.4rem, 1.09rem + 1.33vw, 2rem)
→ どの幅でも h1 > h2 になっている */チェックは最小幅と最大幅の両端で行えば十分です。両端で階層が保たれていれば、直線なので中間でも逆転しません。
| 確認する幅 | 見るポイント | 期待する状態 |
|---|---|---|
| 320px | 下限で止まっているか | 本文16px・見出しが潰れない |
| 768px | 中間でなめらかか | 階層が保たれている |
| 1200px | 上限に達したか | 設計どおりのサイズ |
| 1920px | 上限で止まるか | 1200pxと同じサイズ |
この4点だけ見れば、clamp()の設定ミスはほぼ検出できます。ブラウザの幅を手で動かしながら、文字が飛ばずに変化するかを確認してください。
clamp(最小, 推奨, 最大)は、画面幅に応じてなめらかに変わる値を1行で書ける関数です。第2引数をrem + vwの形にすると、可変にしながらブラウザの文字拡大設定にも反応します。vw単独は拡大が効かず下限も無いため実用には向きません。可変にすべきは見出しと余白で、本文は16〜18pxの狭い範囲に留めます。レイアウトの段階的な切り替えは引き続きメディアクエリの仕事なので、連続量はclamp()、切替はメディアクエリ、と分けて使うのが整理された書き方です。
狙う2点を決めて直線の式を求めます。375pxで28px、1200pxで48pxにしたいなら、傾きは(48−28)÷(1200−375)=0.0242、これを100倍して2.42vw。切片は28−(0.0242×375)=18.9px≒1.18remとなり、clamp(1.75rem, 1.18rem + 2.42vw, 3rem)になります。計算が面倒なら記事内の早見表の値をそのまま使ってください。
2つの問題があります。1つは下限と上限が無いため、狭い画面で読めないほど小さくなり、大画面では巨大になること。もう1つはブラウザの文字サイズ拡大設定にまったく反応しないことです。アクセシビリティの観点から、vw単独の指定は避けてください。
使えますが、変化幅は16px〜18px程度に留めてください。本文が画面幅で大きく動くと読みにくくなります。可変の効果が大きいのは見出しとセクションの余白で、本文はほぼ固定でも問題ありません。
なりません。文字サイズや余白のような連続的に変わる値はclamp()が適していますが、1カラムから2カラムへの切り替えや要素の表示・非表示のような段階的な変化はメディアクエリでしか表せません。役割を分けて併用するのが正解です。
vwはスクロールバーの幅を含むため、100vwを使うと本文領域からはみ出します。幅の指定には%を使い、width: min(92%, 760px)のように書いてください。
CSSの実装テクニックを「レイアウト・装飾・アニメーション・基礎・トラブル解決」の目的別に探せる総まとめページを用意しています。実装で迷ったときの索引としてどうぞ。

目的に合わせて選べる「AI副業」「AI転職」「AI活用」の3コースを用意。副収入・キャリアチェンジ・日常の生産性アップまで、あなたのゴールに合わせてAIを学べます。
会員登録はカンタン30秒で完了します。まずは公式LINEから、無料でAI学習をスタートしましょう!
WithCodeでWeb制作を習得後、フリーランスエンジニアとして活動。HTML/CSS・JavaScript・WordPress案件を中心に年間20件以上の制作実績を持つ。「難しい技術をわかりやすく」をモットーに、初心者〜中級者向けの技術記事を執筆。副業・フリーランス独立を目指す方に向けた情報発信に注力している。
公式サイト より
今すぐ
無料カウンセリング
を予約!