Fluid font-size(フルードフォント)を実装する

Fluid font-size(フルードフォント)を実装する

レスポンシブデザインが当たり前の今、レイアウトはリキッドに、イメージはフルードに。では、テキストは?

フォントサイズはブレイクポイントごとに固定値で指定することが多いと思いますが、今回は、実用的なフルードフォントの実装についてまとめてみます。

サンプル コード

フォントサイズは、ビューポート幅に応じて最小値と最大値の間で流動的に変化し、最大ビューポート幅で最大値となり、最大ビューポート幅以上では最大値で固定されます。

このサンプルコードのポイントは、フォントサイズが極端に小さくなりすぎたり、大きくなりすぎたりしないことと、@media を多用しなくても、最小値を簡潔に設定できることにあります。

<!--  HTML  -->

<div class="sample">
  <p>Fluid font-size</p>
</div>
/*  CSS  */

/*
このサンプルでは、
・フォントサイズ最小値: 10px
・フォントサイズ最大値: 24px
・最小ビューポート幅: 320px
・最大ビューポート幅: 1200px
としています。
このサンプルでは、意味を理解しやすいように、font-size 値の単位に px を使用しています。
*/

.sample p{
  font-size: calc(10px + (24 - 10) / (1200 - 320) * (100vw - 320px) );
  min-height: 0vw;   /* Fix Safari bug with viewport units in calc() */
}
@media screen and (min-width: 1200px){
  .sample p{
    font-size: 24px;
  }
}

サンプル DEMO

このサンプルは、ボックスの右下角をドラッグすることで、ビューポートのサイズに応じた変化をご確認いただけます。

iframe 要素の srcdoc 属性に対応していないブラウザ(IE 11)では表示されません。ほかのブラウザでご確認ください。(マイクロソフトは Internet Explorer の開発を終了しており、利用しないことを呼びかけています。)

resize プロパティに対応していないブラウザ(IE 11 / iOS Safari 13)では、ブラウザウインドウのサイズを変化させたり、デバイスの向きを変えたりしてご確認ください。

コード解説をちょっとだけ

13行目の計算式を読んでいただければ解説は不要かなと思いますが、ちょっとだけ。

最小ビューポート幅を iPhone SE (第1世代) の 320px と想定したとき、最小フォントサイズを 10px にしたいなら単純に、calc( 10 / 320 * 100vw) とすることもできます。iPhone SE (第1世代) で縦表示したとき 100vw は 320px なので、10 / 320 * 320px = 10px となりますから。ですが、PCディスプレイなどビューポート幅 1200px で表示したときには、10 / 320 * 1200px = 37.5px となりますから、ちょっと大き過ぎるでしょうね。

逆に calc( 24 / 1200 * 100vw) とすれば、ビューポート幅 1200px でフォントサイズは 24px になりますが、iPhone SE で縦表示したときには 6.4px となり、小さすぎて可読性を保てません。また、Chrome ブラウザの場合、10px より小さくは表示されません(良心的)。

そこでサンプルでは、最小フォントサイズを 10px として、ビューポート幅 320px のときには 0 が、1200px のときには 14 が加算されます。したがって、フォントサイズは 10〜24px の範囲で、ビューポートに応じてフルードに表示されます。なおビューポート幅 1200px 以上では、メディアクエリで 24px に固定しています。

言葉で説明しようとするとややこしく感じますね。やっぱり解説は不要だったでしょうか。

[2020-04-20 追記] Safari でリサイズ時に、ビューポート(vw)単位を含む calc が評価されない現象を確認しました。バグフィックスとして、"min-height: 0vw" を追加しました。

おわりに

実際にはブレイクポイントごとに、rem で指定するか、レイアウトバランスの保持が必要な場合には vw で指定するケースが多いと思います。が、メディアクエリを多用したり、最小フォントサイズを気にしたりと、コードが煩雑になりがちです。

サンプルのような実装も選択肢に持ちながら、案件ごとに柔軟な対応ができるとよいのかなと思います。