デザイン・色彩

font-size vw と clamp() でレスポンシブな文字サイズを指定する

CSSにおいて、レスポンシブ対応って本当に大変です。各種デバイスの画面サイズに合わせてブレイクポイントをいくつか設けて、レイアウト調整をしていきますが、同じブレイクポイントの中でも画面サイズによって意図しないレイアウトになったり、崩れたり、試行錯誤が続いたりします。

フォントサイズについても同様で、ブレイクポイントに応じて、よりも、もっと画面サイズに応じて柔軟に可変するような事出来ないだろうかと思ってました。

そんな中、なかなか良いプラクティスを見つけました。こちらを参考に試行してみました。

font-size vw だけで指定する場合
画面幅に比例して文字が無限に伸び縮みします。clamp(最小, calc(rem + vw), 最大) で上下限を決めると、レスポンシブな font-size を安全に使えます。
例: font-size: clamp(1rem, calc(0.625rem + 0.625vw), 1.25rem);

font-size vw」「レスポンシブ font-size」「clamp フォントサイズ」で探している方向けに、vwclamp() を組み合わせた実践例をまとめました。メディアクエリのブレイクポイントだけでは届かない微調整に向いています。

先に結論(コピペ例)

画面幅に応じて文字サイズをなめらかに変える最小例です(ルート font-size: 16px 想定)。

.responsive-text {
  font-size: clamp(1.2rem, calc(1rem + 0.625vw), 1.7rem);
}

タイポグラフィまわりの続き — 実装チュートリアルは 学習ハブReact Todo(初学者向け①) も参照してください。

はじめに

本記事では、CSSにおける可変フォントサイズの実装について記載しています。以下のような方にお薦めです。

  • レスポンシブデザインにおけるフォントサイズの扱いについて良いソリューションをお探しの方
  • CSSのカスタムプロパティを扱いたい方、知りたい方
  • HTML+CSSを普段使ってる方
  • HTML+CSSに興味のある方、勉強中の方

今回の内容がベストプラクティスとまでは言えないかも知れませんが、個人的にはこれは使えるなぁと思った次第です。

1. 単位について

まずは、CSSでサイズ指定する場合に利用される単位のおさらいです。

単位意味
px1/96インチ、固定値
%親要素のフォントサイズの〇%
em親要素に設定されているフォントサイズの〇倍
1em=親要素に設定されているフォントサイズ
remHTML1要素のフォントサイズの〇倍
1rem=HTMLに設定されているフォントサイズ(デフォルトは1rem=16px)
vwビューポートの幅(画面幅)の〇%
1vw=ビューポート幅の1%
vhビューポートの高さの〇%
1vh=ビューポートの高さの1%

pxは固定値なので、必然的に別の選択肢(あるいは別の選択肢の組み合わせ)になってくると思います。

なお、vw(幅指定)とvh(高さ指定)はCSSではよく利用されてる方も多いと思いますが、表示されている画面サイズに対する、割合を指定出来るので、非常に重宝します。

2. 指定方法いろいろ

元記事で挙げられている方法をそのまま記載しますが、フォントサイズ指定のテクニックとしては、以下の候補があります。

  1. px/rem × メディアクエリ(おすすめ度★★、一般的なので初心者向け☺)
    最も一般的な手法で、ブレイクポイントを指定し、フォントサイズを変化させるもの。指定したブレイクポイントで、段階的にサイズが変化。ブレイクポイントが多数必要、画面幅に応じてフォントサイズは変化しない。
  2. vw(おすすめ度★)
    フォントサイズをvwで指定する方法。
    vwで指定すると、常に画面幅の変化に応じてフォントサイズも変化。
    ただし、フォントサイズが小さくなりすぎたり、大きくなりすぎたりする
  3. calc × rem × vw(おすすめ度★★)
    ルートにvwを設定、フォントサイズは画面幅に応じて変化、1rem=10pxで設定すれば指定もしやすい。ただし、フォントサイズが小さくなりすぎたり、大きくなりすぎたりする
  4. calc × rem × vw × clamp(おすすめ度★★★)
    clamp関数で(最小値, vwを使った可変の推奨値, 最大値)を設定。大きすぎたり小さすぎたりを回避。

このうち、お薦めは、4.のclampを利用したもので、こちらを試してみました。
clampは CSS の関数で、値を上限と下限の間に制限します。 clamp() によって、定義された最大値と最小値の間の値を選択することができます。最小値、推奨値、最大値の3つの引数を取ります。

なお、色々計算が必要ですので、px→vw変換ツールを利用すると効率的です。

3. CSS実装

という事で、実際に取り入れてみました。
参考記事の方では、calc × rem × vw × clamp 方式は、以下のような記載になっています。

/*基準を1rem=10pxに設定*/
html {
    font-size: 62.5%;
}

/*最小値:1.1rem → 可変(0.9rem + 0.625vw(画面幅320px:2px, 800px:5px, 1200px:7.5px))→ 最大値:1.6rem*/
.font-size-S {
    font-size: clamp(1.1rem, calc(0.9rem + 0.625vw), 1.6rem);
}

/*最小値:1.2rem → 可変(1rem + 0.625vw(画面幅320px:2px, 800px:5px, 1200px:7.5px))→ 最大値:1.7rem*/
.font-size-M {
    font-size: clamp(1.2rem, calc(1rem + 0.625vw), 1.7rem);
}

/*最小値:1.6rem → 可変(2.2rem + 0.625vw(画面幅320px:2px, 800px:5px, 1200px:7.5px))→ 最大値:2.9rem*/
.font-size-L {
    font-size: clamp(2.4rem, calc(2.2rem + 0.625vw), 2.9rem);
}

これだと少々ややこしいのと、個人的には、最小幅と最大幅があり、その中で可変出来ればOKと考えたので、以下のように定義しました。CSSのカスタムプロパティ(変数)を利用しています。

:root {

/* font-size設定 */

  --f64: clamp(2rem, 5vw, 4rem); /*1280px以上は64pt、640px以下は32px、その間は可変*/
  --f36: clamp(1.13rem, 2.81vw, 2.25rem);/*1280px以上は36pt、640px以下は18px、その間は可変*/
  --f24: clamp(0.9rem, 1.875vw, 1.5rem);/*1280px以上は24pt、640px以下は14.4px、その間は可変*/
  --f20: clamp(0.75rem, 1.563vw, 1.25rem);/*1280px以上は20pt、640px以下は12px、その間は可変*/
  --f16: clamp(0.625rem, 1.25vw, 1rem);/*1280px以上は16pt、640px以下は10x、その間は可変*/
  --f14: clamp(0.625rem, 1.09vw, 0.875rem);/*1280px以上は14pt、640px以下は10x、その間は可変*/
  --f12: clamp(0.56rem, 0.94vw, 0.75rem);/*1280px以上は14pt、640px以下は9x、その間は可変*/
}

解説します。まず、基準として計算した画面サイズは幅1280pxとしました。

最初の–f64を説明します。これは、CSSのカスタムプロパティでの指定ですが、画面幅1280px時に64pxとなるよう、5vwを中央で指定しています(1280×5%=64)。そして中央を挟んだ、前の最小値と後ろの最大値は、デフォルトのフォントサイズは、1rem=16pxですので、それぞれ、2rem=32px、4rem=64pxの指定です。

このフォントサイズ、最小値32px、最大値64pxの間で、画面サイズに応じて、5vwで表示すると言う指定です。5vwは画面幅1280pxの時は64px、640pxの時は32px(640×5%)となります。例えば画面幅が960pxであれば、960×5%=48pxの表示となります。

他のフォントサイズも同じような考えで設定しています。画面幅1280px以上の際に64,36,24,20,16,14,12(全て単位はpx)のサイズセットを設定してます。なお、最小値は、フォントサイズが小さくなるほど、半分にすると小さくなりすぎるので、調整をしています(例えばf14は最小値は半分の7pxではなく、10pxになど)。

実際にHTMLに記述して試してみます。

<!DOCTYPE html>
<html lang="ja">

<head>
  <title>Font Size Responsive</title>
  <meta name="description" content="Font Size Responsive">
  <meta charset="UTF-8">
  <style>
    :root {

      /* font-size設定 */
      --f64: clamp(2rem, 5vw, 4rem);
      /*1280px以上は64pt、640px以下は32px、その間は可変*/
      --f36: clamp(1.13rem, 2.81vw, 2.25rem);
      /*1280px以上は36pt、640px以下は18px、その間は可変*/
      --f24: clamp(0.9rem, 1.875vw, 1.5rem);
      /*1280px以上は24pt、640px以下は14.4px、その間は可変*/
      --f20: clamp(0.75rem, 1.563vw, 1.25rem);
      /*1280px以上は20pt、640px以下は12px、その間は可変*/
      --f16: clamp(0.625rem, 1.25vw, 1rem);
      /*1280px以上は16pt、640px以下は10x、その間は可変*/
      --f14: clamp(0.625rem, 1.09vw, 0.875rem);
      /*1280px以上は14pt、640px以下は10x、その間は可変*/
      --f12: clamp(0.56rem, 0.94vw, 0.75rem);
      /*1280px以上は14pt、640px以下は9x、その間は可変*/
    }

    .f64 {
      font-size: var(--f64);
      /*フォントサイズの変数を割り当て*/
    }

    .f36 {
      font-size: var(--f36);
    }

    .f24 {
      font-size: var(--f24);
    }

    .f20 {
      font-size: var(--f20);
    }

    .f16 {
      font-size: var(--f16);
    }

    .f14 {
      font-size: var(--f14);
    }

    .f12 {
      font-size: var(--f12);
    }
  </style>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>

<body>

  <div class="f64">これはf64のフォントサイズです。</div>
  <div class="f36">これはf36のフォントサイズです。</div>
  <div class="f24">これはf24のフォントサイズです。</div>
  <div class="f20">これはf20のフォントサイズです。</div>
  <div class="f16">これはf16のフォントサイズです。</div>
  <div class="f14">これはf14のフォントサイズです。</div>
  <div class="f12">これはf12のフォントサイズです。</div>

</body>

</html>

styleの設定は、HTMLの中に記述する形としてます。それぞれのフォントサイズのクラスを定義し、CSSのカスタムプロパティとして設定した変数を各クラスに割り当てています。この割当は、var(変数名)で指定します。

HTMをブラウザに表示してブラウザの横幅を動かすと以下のGIFアニメのようにフォントサイズが幅に合わせて変化します。

これで比較的柔軟にフォントサイズを変化させることが出来ました。レスポンシブデザインでブレイクポイントの狭間のレイアウトとか悩ましいですが、この可変フォントサイズは色々と活用できそうです。

下記は、オンラインショップのデザインプロトですが、こちらでも、このレスポンシブなフォントサイズ指定を利用してみました。
CRAFTS DESIGN SHOP PROTO

よくある質問

font-size に vw だけを使ってもいいですか?

小さい画面では文字が読みづらく、大きい画面では見出しが肥大化しやすいです。本記事のように clamp() で最小・最大を決め、真ん中に vwcalc(rem + vw) を入れる方法が無難です。

font-size vw と clamp() の違いは?

font-size: 2vw は画面幅のみで決まります。clamp(1rem, 2vw, 1.5rem) は 2vw を推奨値としつつ、1rem 未満・1.5rem 超過にならないよう制限します。

レスポンシブな font-size とメディアクエリの違いは?

メディアクエリはブレイクポイントでサイズが段階的に変わります。clamp(最小, 推奨, 最大) は画面幅に応じてなめらかに変化し、極端に小さく/大きくなりすぎないよう上下限で止めます。

0.625rem は何 px ですか?

ブラウザ既定(html { font-size: 16px })なら 0.625rem = 10px です。本記事の html { font-size: 62.5% } を使う場合は 1rem = 10px になるため、0.625rem = 約 6.25px になります。px 換算はルート設定に依存します。

clamp() の最小・推奨・最大はどう決めますか?

最小は読みやすさの下限、最大は見出しや本文の上限、推奨値に vwcalc(rem + vw) を入れて可変幅を作ります。本記事の --f16: clamp(0.625rem, 1.25vw, 1rem) はその一例です。

html { font-size: 62.5% } は計算しやすいテクニックですが、現代のプロジェクトではルートを変えず rem / clamp を使う方法も一般的です。

シリーズ一覧を見る