1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【CSS】calc()とclamp()で作るフルードタイプスケール実装ガイド

Last updated at Posted at 2025-02-23

下記がとても実践的で参考になったので、情報を補足しながら紹介します。

はじめに

Webデザインにおいて、文字サイズの一貫性とレスポンシブ性は重要な要素です。特に異なるデバイスやビューポートサイズに対して、スムーズに適応する文字サイズの実装は、多くの開発者が直面する課題となっています。

従来、このような適応型のタイポグラフィを実現するには、JavaScriptを使用したり、複雑なCSSの計算を行ったりする必要がありました。しかし、モダンなCSSの機能であるcalc()clamp()、CSS変数を組み合わせることで、よりシンプルかつ効果的な解決策を実現できます。

前提知識

この記事を理解するために必要な知識:

  • CSSの基本的な理解
  • CSS変数(カスタムプロパティ)の基本
  • レスポンシブデザインの概念
  • モダンブラウザでのCSS機能サポート

実装の基本概念

calc()関数の仕組み

calc()関数は数値計算を行うCSS関数ですが、いくつかの重要な制限があります:

  1. 単位なしの数値とピクセル値の暗黙的な変換ができない

    • calc(5px + 5) は無効な式
    • calc(5px + 5px) のように単位をそろえる必要がある
  2. ピクセル値同士の除算ができない

    • calc(10px / 2px) は無効
    • calc(10px / 2) のように除数は単位なしの数値にする
  3. ピクセル値同士の乗算ができない

    • calc(5px * 2px) は無効
    • calc(5px * 2) のように片方は単位なしの数値にする

これらの制限を回避するため、以下の巧みな戦略が紹介されています:

:root {
  /* 単位なしの数値として定義 */
  --min-size: 12;    /* 最小フォントサイズ */
  --max-size: 18;    /* 最大フォントサイズ */
  --container-min: 320;  /* 最小コンテナ幅 */
  --container-max: 2400; /* 最大コンテナ幅 */
}

.container-adaptive {
  /* サイズの計算 */
  --font-size: calc(
    /* 基本サイズ(単位なしの数値にピクセル単位を適用) */
    var(--min-size) * 1px +
    /* 最大サイズと最小サイズの差分 */
    (var(--max-size) - var(--min-size)) *
    /* コンテナサイズの現在位置を計算 */
    (100cqw - var(--container-min) * 1px) /
    /* コンテナサイズの範囲で正規化 */
    (var(--container-max) - var(--container-min))
  );
}

clamp()関数による範囲の制御

clamp()関数は値を指定された範囲内に収める機能を提供します:

.container-adaptive {
  /* clamp(最小値, 推奨値, 最大値) */
  font-size: clamp(
    var(--min-size) * 1px,    /* これより小さくならない */
    var(--font-size),         /* 可能ならこの値を使用 */
    var(--max-size) * 1px     /* これより大きくならない */
  );
}

この組み合わせにより、以下の利点が得られます:

  1. 適切な範囲での制御

    • 最小値以下にならない
    • 最大値以上にならない
    • その間は計算された値を使用
  2. スムーズな変化

    • ビューポートサイズの変化に応じて連続的に変化
    • 急激な変化を避けられる

実装パターン

ビューポートベースの実装

ブラウザウィンドウ全体を基準にする場合:

.viewport-adaptive {
  /* ビューポート幅に基づく計算 */
  --font-size: calc(
    var(--min-size) * 1px +
    (var(--max-size) - var(--min-size)) *
    /* 100vwはビューポート幅全体を表す */
    (100vw - var(--viewport-min) * 1px) /
    (var(--viewport-max) - var(--viewport-min))
  );
  font-size: clamp(
    var(--min-size) * 1px,
    var(--font-size),
    var(--max-size) * 1px
  );
}

コンテナベースの実装

特定のコンテナ要素を基準にする場合:

/* コンテナの定義 */
.container {
  /* コンテナクエリの有効化 */
  container-type: inline-size;
  container-name: main;
}

.container-adaptive {
  --font-size: calc(
    var(--min-size) * 1px +
    (var(--max-size) - var(--min-size)) *
    /* 100cqwは現在のコンテナ幅を表す */
    (100cqw - var(--container-min) * 1px) /
    (var(--container-max) - var(--container-min))
  );
  font-size: clamp(
    var(--min-size) * 1px,
    var(--font-size),
    var(--max-size) * 1px
  );
}

/* コンテナクエリの使用例 */
@container main (min-width: 400px) {
  .container-adaptive {
    /* コンテナが400px以上の時のスタイル */
  }
}

実装の際は、以下の点に考慮が必要かもしれません:

  • デザインシステムの粒度
  • コンポーネントの再利用性
  • ブラウザサポートの要件(コンテナクエリは比較的新しい機能)

スケーラブルなユーティリティクラスの作成

再利用可能なタイプスケールを構築するために、ユーティリティクラスを設定します:

/* ベースとなる変数の定義 */
:root {
  --scale: 1.25;  /* スケール比率 */
  --base-size: 1rem;  /* 基準サイズ */

  /* ビューポート/コンテナの制約 */
  --min-viewport: 320;
  --max-viewport: 2400;
}

/* スケールレベルの定義 */
.text-md, .text-lg, .text-xl {
  container-type: inline-size;
}

/* 中サイズテキスト */
.text-md {
  --min-size: 14;
  --max-size: 16;
  font-size: clamp(
    var(--min-size) * 1px,
    calc(var(--min-size) * 1px + (var(--max-size) - var(--min-size)) *
    (100cqw - var(--min-viewport) * 1px) /
    (var(--max-viewport) - var(--min-viewport))),
    var(--max-size) * 1px
  );
}

/* 大サイズテキスト */
.text-lg {
  --min-size: 16;
  --max-size: 20;
  font-size: clamp(
    var(--min-size) * 1px,
    calc(var(--min-size) * 1px + (var(--max-size) - var(--min-size)) *
    (100cqw - var(--min-viewport) * 1px) /
    (var(--max-viewport) - var(--min-viewport))),
    var(--max-size) * 1px
  );
}

/* 特大サイズテキスト */
.text-xl {
  --min-size: 20;
  --max-size: 24;
  font-size: clamp(
    var(--min-size) * 1px,
    calc(var(--min-size) * 1px + (var(--max-size) - var(--min-size)) *
    (100cqw - var(--min-viewport) * 1px) /
    (var(--max-viewport) - var(--min-viewport))),
    var(--max-size) * 1px
  );
}

使用例:

<div class="container">
  <h1 class="text-xl">大見出し</h1>
  <h2 class="text-lg">中見出し</h2>
  <p class="text-md">本文テキスト</p>
</div>

現在の制限事項

  1. ブラウザサポート

    • コンテナクエリ(cqw)は比較的新しい機能
    • フォールバックの実装を検討する必要がある
  2. パフォーマンスへの影響

    • 複雑な計算を含むため、大量の要素に適用する場合は注意が必要

注:参考記事ではcalc()関数でのrem単位の使用に制限があるとされていますが、現在の主要なモダンブラウザではこの制限は解除されており、rem単位を自由に使用できます。

トラブルシューティング

デバグが大変だという感想を持ちました。

ありそうな問題と解決方法

  1. 計算結果が期待通りでない

    • 単位の使用方法を確認(単位なしの数値とピクセル値の混在に注意)
    • clamp()の最小値と最大値が適切か確認
  2. スムーズな変化が見られない

    • コンテナ/ビューポートの最小値と最大値の範囲が適切か確認
    • 中間値の計算が正しく行われているか確認
  3. 古いブラウザでの対応

/* フォールバックの実装例 */
.adaptive-text {
  /* 基本サイズをフォールバックとして設定 */
  font-size: 16px;
  /* モダンブラウザ向けの実装 */
  font-size: clamp(var(--min-size) * 1px, var(--font-size), var(--max-size) * 1px);
}

まとめ

フルードタイプスケールは、モダンなCSSの機能を活用することで、より柔軟でレスポンシブなタイポグラフィを実現します。本記事で紹介した実装方法には以下の利点があります:

  • メンテナンス性の高いCSS変数の活用
  • ブレイクポイントに依存しない連続的な変化
  • コンポーザブルなユーティリティクラスによる柔軟な設定

これらの技術を適切に組み合わせることで、より洗練されたWebタイポグラフィを実現できます。

参考文献

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?