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

画面幅ベースのフォントサイズ定義

問題

基本的なclamp()タイポグラフィは、ビューポート範囲全体にわたってフォントサイズを線形にスケーリングします。シンプルなケースではこれで十分ですが、特定のブレークポイント範囲内でテキストのスケーリングを精密に制御したい場合には不十分です。たとえば、サイトロゴに次のような要件があるとします:

  • lgブレークポイント範囲(1024-1280px)では15-24px
  • xl範囲(1280-1536px)では24-30px
  • 2xl範囲(1536-1920px)では30-36px

単一のclamp()ではこの区間ごとのスケーリングを表現できません。メディアクエリで固定サイズを指定すると急激な変化が生じ、単一のclampでは各ブレークポイント境界で正確なサイズを実現できません。

解決方法

ブレークポイントごとのメディアクエリ範囲ごとのclamp()を組み合わせます。各ブレークポイントが独自のclamp()を持ち、その範囲内で滑らかにスケーリングします。範囲同士は、一つの範囲の最大値が次の範囲の最小値と一致するようにつなぎ合わせます。

この記事はclamp()を使った流体フォントサイズの内容を前提としています。基本的なclamp()の使い方を理解してから読み進めてください。

計算式

ブレークポイント範囲startVwからendVwで、フォントサイズをminSizeからmaxSizeにスケーリングする場合:

slope = (maxSize - minSize) / (endVw - startVw)
intercept = minSize - slope × startVw

これにより次のように記述できます:

font-size: clamp(minSize, calc(intercept + slope × 1vw), maxSize);

たとえば、1024px-1280pxの範囲で15px→24pxにスケーリングする場合:

slope = (24 - 15) / (1280 - 1024) = 9 / 256 ≈ 0.03516 (3.516vw)
intercept = 15 - 0.03516 × 1024 = 15 - 36 ≈ -21px

結果:clamp(15px, calc(-21px + 3.516vw), 24px)

検算: 1024pxのとき → calc(-21 + 0.03516 × 1024) = calc(-21 + 36) = 15px。1280pxのとき → calc(-21 + 0.03516 × 1280) = calc(-21 + 45) = 24px。

コード例

基本的な区間別フォントサイズ

.site-title {
/* Base: fixed size for small screens */
font-size: 15px;
}

/* lg: 1024px – 1280px → scale 15px to 24px */
@media (min-width: 1024px) {
.site-title {
font-size: clamp(15px, calc(-21px + 3.516vw), 24px);
}
}

/* xl: 1280px – 1536px → scale 24px to 30px */
@media (min-width: 1280px) {
.site-title {
font-size: clamp(24px, calc(-6px + 2.344vw), 30px);
}
}

/* 2xl: 1536px – 1920px → scale 30px to 36px */
@media (min-width: 1536px) {
.site-title {
font-size: clamp(30px, calc(6px + 1.563vw), 36px);
}
}

注意:以下のデモではプレビューiframe内で流体スケーリングが見えるよう、縮小したブレークポイント(320px / 500px / 768px)を使用しています。上記のコード例は本番環境に適したブレークポイントを示しています。

区間別の流体フォントサイズ -- モバイルとフルビューポートを切り替えてスケーリングを確認

デザイントークンシステムによる区間別スケーリング

各フォントサイズステップがブレークポイントごとに独立してスケーリングする、再利用可能なトークンシステムを定義します:

:root {
/* Small screens: fixed base sizes */
--font-size-display: 24px;
--font-size-title: 20px;
--font-size-heading: 18px;
--font-size-body: 16px;
}

/* lg: 1024px – 1280px */
@media (min-width: 1024px) {
:root {
--font-size-display: clamp(28px, calc(-4px + 3.125vw), 36px);
--font-size-title: clamp(22px, calc(-2px + 2.344vw), 28px);
--font-size-heading: clamp(18px, calc(2px + 1.563vw), 22px);
--font-size-body: clamp(16px, calc(8px + 0.781vw), 18px);
}
}

/* xl: 1280px – 1536px */
@media (min-width: 1280px) {
:root {
--font-size-display: clamp(36px, calc(-24px + 4.688vw), 48px);
--font-size-title: clamp(28px, calc(-12px + 3.125vw), 36px);
--font-size-heading: clamp(22px, calc(2px + 1.563vw), 26px);
--font-size-body: clamp(18px, calc(8px + 0.781vw), 20px);
}
}
デザイントークンのフォントサイズ -- 各ステップがブレークポイントごとに独立してスケーリング

任意の範囲に対するclamp()値の計算方法

任意のビューポート範囲に対するclamp()のpreferred値を計算するステップバイステップの例です。

目標: ビューポート1024pxで22px、1280pxで28pxにフォントをスケーリングする。

Step 1: Calculate the slope
slope = (28 - 22) / (1280 - 1024)
= 6 / 256
≈ 0.02344

Step 2: Calculate the intercept (base offset in px)
intercept = minSize - slope × startVw
= 22 - 0.02344 × 1024
≈ 22 - 24
= -2px

Step 3: Assemble the clamp()
font-size: clamp(22px, calc(-2px + 2.344vw), 28px);

検算: ビューポート1024pxのとき → calc(-2 + 0.02344 × 1024) = calc(-2 + 24) = 22px。1280pxのとき → calc(-2 + 0.02344 × 1280) = calc(-2 + 30) = 28px。

ページヘッダーの実例

サイトヘッダーのロゴテキストが全ブレークポイントで滑らかにスケーリングする実践的な例です:

区間別の流体ロゴテキストを持つサイトヘッダー -- モバイルとフルビューポートを比較

AIがよくやるミス

  • ブレークポイントごとの精密な制御が必要な場面で、ビューポート範囲全体に単一のclamp()を使ってしまう -- 範囲ごとにスケーリング速度を調整できません
  • ある範囲のmaxと次の範囲のminを揃え忘れ、ブレークポイント境界で目に見えるジャンプが発生する(例:lgの最大値が24pxなのにxlの最小値が26pxだと2pxのジャンプが生じます)
  • 計算式を間違える -- 分母はビューポート範囲(endVw - startVw)であり、(endVw - minSize)ではありません。ビューポート幅とフォントサイズを混同すると、傾きが不正確になります
  • calc()オフセットなしでvwのみを使う -- font-size: 2vwはビューポート1000pxで20pxになりますが、開始位置と停止位置を制御できません
  • 本文テキストや小さなUIラベルに区間別clampを適用する -- このテクニックはディスプレイテキストやタイトルに最適であり、単一のclamp()や固定サイズで十分な場合には不要です
  • 計算を検算しない -- calc(intercept + slope × startVw)が意図した最小サイズと等しくなることを必ず確認してください

使用場面

  • サイトロゴやブランドテキスト -- 特定のブレークポイントで正確なサイズにする必要がある場合
  • デザイントークンのフォントサイズ定義 -- 各トークンステップが独立したスケーリング動作を必要とする場合
  • ディスプレイ見出し -- ヒーローセクションでビューポート範囲ごとに異なるスケーリング速度が必要な場合
  • あらゆる要素 -- 単一のclamp()ではスケーリングカーブを十分に制御できない場合

以下の場合は単一のclamp()clamp()を使った流体フォントサイズを参照)を使いましょう:

  • スケーリング範囲がシンプルな場合(全ビューポートで一つのmin→一つのmax)
  • ブレークポイント境界でのピクセル単位の精密な制御が不要な場合
  • シンプルなレスポンシブテキストに最小限のCSSで対応したい場合

参考リンク