メインコンテンツまでスキップ
  • Created:
  • Updated:
  • Author:
    Takeshi Takatsudo

clamp() による流体サイジング

問題

従来のレスポンシブデザインは、特定のブレークポイントでサイズを変更するメディアクエリに依存しています。これは急激な変化を生みます。見出しがモバイルでは 2rem で、デスクトップでは突然 3rem になるといった具合です。AIエージェントはフォントサイズ、パディング、幅に対して複数のメディアクエリを生成しがちで、冗長で保守しにくいCSSになります。clamp() 関数は、1つの宣言でメディアクエリゼロのまま、最小値と最大値の間をスムーズに流体スケーリングすることでこの問題を解決します。

解決方法

clamp() 関数は3つの値を取ります:

clamp(minimum, preferred, maximum)
  • minimum — 値が取りうる最小値
  • preferred — 流体的にスケールするビューポート相対の式
  • maximum — 値が取りうる最大値

ブラウザは preferred 値を使用しますが、minimum と maximum の間に制約します。preferred 値が minimum より小さい場合は minimum が使われ、maximum より大きい場合は maximum が使われます。

コード例

流体タイポグラフィ

h1 {
font-size: clamp(1.75rem, 1rem + 2.5vw, 3rem);
}

h2 {
font-size: clamp(1.375rem, 0.875rem + 1.5vw, 2rem);
}

p {
font-size: clamp(1rem, 0.875rem + 0.4vw, 1.25rem);
}

見出しは狭いビューポートの 1.75rem から広いビューポートの 3rem までスムーズにスケールします。1rem + 2.5vw の preferred 値は固定のベースとビューポート相対の部分を組み合わせており、ユーザーがズームした場合でもテキストがスケールします。

rem + vw であって、vw だけではない理由

/* Bad: pure vw ignores user zoom preferences */
h1 {
font-size: clamp(1.75rem, 4vw, 3rem);
}

/* Good: rem + vw respects user zoom */
h1 {
font-size: clamp(1.75rem, 1rem + 2.5vw, 3rem);
}

preferred 値に vw だけを使うと、ユーザーがブラウザのズームレベルを変更してもテキストがスケールしません(WCAGアクセシビリティ要件に違反します)。rem + vw を組み合わせることで、テキストがビューポート幅とズーム設定の両方に応答します。

preferred 値の計算方法

最小ビューポートでの最小サイズから最大ビューポートでの最大サイズまで線形にスケールするには:

slope = (maxSize - minSize) / (maxViewport - minViewport)
intercept = minSize - slope × minViewport
preferred = intercept(rem) + slope × 100(vw)

例:320px で 1.75rem から 1280px で 3rem にスケール:

slope = (3 - 1.75) / (80 - 20) = 1.25 / 60 = 0.02083
intercept = 1.75 - 0.02083 × 20 = 1.3334
preferred = 1.3334rem + 2.083vw

(ビューポート幅は16で割って rem に変換:320/16=20、1280/16=80)

h1 {
font-size: clamp(1.75rem, 1.333rem + 2.083vw, 3rem);
}

実際には、手計算ではなく clamp 計算ツールを使いましょう。

流体スペーシング

clamp() はタイポグラフィだけでなく、padding、margin、gap にも使えます:

.section {
padding-block: clamp(2rem, 1rem + 3vw, 5rem);
}

.card-grid {
gap: clamp(1rem, 0.5rem + 1.5vw, 2.5rem);
}

.container {
padding-inline: clamp(1rem, 0.5rem + 2vw, 4rem);
}
clamp(): clamp() による流体幅
clamp(): clamp() による流体パディング

流体幅の制約

.content {
max-inline-size: clamp(30rem, 90%, 60rem);
}

コンテンツエリアは最小 30rem、最大 60rem で、その間はコンテナの90%にスケールします。

完全な流体タイポグラフィシステム

:root {
--text-sm: clamp(0.875rem, 0.8rem + 0.2vw, 1rem);
--text-base: clamp(1rem, 0.875rem + 0.4vw, 1.25rem);
--text-lg: clamp(1.25rem, 1rem + 0.75vw, 1.75rem);
--text-xl: clamp(1.5rem, 1.125rem + 1.25vw, 2.25rem);
--text-2xl: clamp(1.875rem, 1.25rem + 2vw, 3rem);
--text-3xl: clamp(2.25rem, 1.25rem + 3vw, 4rem);

--space-sm: clamp(0.5rem, 0.375rem + 0.4vw, 0.75rem);
--space-md: clamp(1rem, 0.75rem + 0.75vw, 1.5rem);
--space-lg: clamp(1.5rem, 1rem + 1.5vw, 3rem);
--space-xl: clamp(2rem, 1rem + 3vw, 5rem);
}

メディアクエリの置き換え

/* Before: multiple breakpoints */
h1 {
font-size: 1.75rem;
}
@media (min-width: 640px) {
h1 { font-size: 2rem; }
}
@media (min-width: 768px) {
h1 { font-size: 2.5rem; }
}
@media (min-width: 1024px) {
h1 { font-size: 3rem; }
}

/* After: one line, smooth scaling */
h1 {
font-size: clamp(1.75rem, 1rem + 2.5vw, 3rem);
}

AIがよくやるミス

  • preferred 値に vw だけを使っている。 font-size: clamp(1rem, 3vw, 2rem) はユーザーがブラウザをズームしてもスケールせず、WCAG 1.4.4に違反します。preferred 値では常に rem + vw を組み合わせましょう。
  • clamp() の方がシンプルなのに、フォントサイズに複数のメディアクエリを生成している。 1つの clamp() 宣言で3〜4個のメディアクエリを置き換えられ、よりスムーズなスケーリングが実現できます。
  • min と max を逆にしている。 minimum 値が maximum より大きい場合、clamp() は常に minimum を返します。min < max であることを必ず確認しましょう。
  • min と max の値に rem ではなく px を使っている。 rem を使うことで、ユーザーのフォントサイズ設定やズーム設定が尊重されます。
  • スペーシングに clamp() を使っていない。 AIエージェントはフォントサイズには clamp() を使う一方で、padding、margin、gap にはまだメディアクエリを使うことがあります。これらすべてが流体スケーリングの恩恵を受けます。
  • preferred 値を複雑にしすぎている。 式はピクセルパーフェクトである必要はありません。本文テキストには clamp(1rem, 0.875rem + 0.5vw, 1.25rem) で十分です。特定のビューポート幅間の正確な線形補間が必要になることはほとんどありません。
  • clamp() を不必要に calc() の中にネストしている。 clamp() はすでに内部で数式を評価します。calc(clamp(...)) は冗長です。

使い分け

clamp() が最適な場面

  • モバイルとデスクトップ間でスムーズにスケールすべきフォントサイズ
  • ビューポートに応じて大きくなるセクションの padding と margin
  • 柔軟な制約を持つコンテナ幅
  • grid/flex レイアウトの gap 値
  • 現在2つ以上のメディアクエリを使ってスケールしている値すべて

メディアクエリを使い続ける場面

  • プロパティをまったく別の値に変更する必要がある場合(スケールされた版ではなく)
  • サイズのスケーリングではなくレイアウトの切り替え(例:1カラムからサイドバーへの切り替え)
  • スケーリングが線形でない場合(例:特定のブレークポイントでサイズがジャンプすべき場合)

アクセシビリティ要件

  • preferred 値では常に rem + vw を使い、vw だけは避けましょう
  • ブラウザの200%ズームでテキストが読みやすいことをテストしましょう
  • ビューポート全体で本文テキストが45〜75文字の行長範囲に収まることを確認しましょう

参考リンク