CSSのvw, calc()を使用した、レスポンシブ対応のフォントサイズを指定するこれからのテクニック
Post on:2020年3月23日
本文や見出しなどのフォントサイズをスマホ時やデスクトップ時で変える時、通常はMedia Queriesでスクリーンサイズごとに文字サイズを指定していると思います。
ここで紹介するフォントサイズの指定方法はちょっと新しいアプローチで、最初にベースとなるフォントサイズを設定し、スクリーンサイズが大きくなるにつれ、Viewport Unit(ビューポートの単位)で加算してサイズを大きくします。
Viewport Unit Based Typography
以下、各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様に許可を得て翻訳しています。
- Viewport Unit(ビューポートの単位)とは?
- フォントのサイズ指定のためのビューポートの使い方
- 他の文字の要素をビューポートで指定
- 縦のリズムとモジュラースケールをビューポートで指定
- フォントサイズの指定の精度をアップする
- さらに精度をアップする
- まとめ
- 補足
Viewport Unit(ビューポートの単位)とは?
現在、CSSで利用できるViewport Unit(ビューポートの単位)は、4種類です。
-
- vw
- ビューポートの幅のパーセント
-
- vh
- ビューポートの高さのパーセント
-
- vmin
- vwかvhの最小値
-
- vmax
- vwかvhの最大値
vminがIE9で、vmaxがIE10-Edgeで利用できませんが、ここでは「vw」のみを利用するので、ほとんどのブラウザで使用できます。
参考: Viewport units(vw, vh, vmin, vmax)の各ブラウザのサポート状況
ビューポートとは、ブラウザの幅と高さのサイズに依存します。
1vwはブラウザの幅の1%、100vwはブラウザの幅の100%を意味します。
100vm と 100vh
ビューポートの利点は、ビューポートが変化した時はいつでもその値が自動的に再計算されることで、ページをロードした時、リサイズした時、向きを変えた時、すべてで自動的に再計算されます。
例えば幅と高さを1/2にして、面積を全体の1/4に指定した場合、どんな時でも必ず1/4になるコンポーネントを簡単に作成することができます。
1 2 3 4 5 |
.component { width: 50vw; height: 50vh; background: rgba(255, 0, 0, 0.25) } |
全体の1/4の大きさのコンポーネント
Viewport Unit(ビューポートの単位)の基本はこれだけでOKです。
さっそく、ビューポートを使ったフォントサイズの指定を解説します。
フォントのサイズ指定のためのビューポートの使い方
フォントのサイズ指定にビューポートの単位を使う一番の理由は、この単位がクライアントのブラウザによって自動的に計算し直されるからです。これはMedia Queriesで個別にサイズ指定をする必要がないことを意味します。
この問題がはっきりと分かる例を見てみましょう。
下記はMedia Queriesを使い、800pxのブレイクポイントでフォントのサイズを16pxから20pxに変更するコードです。
1 2 3 4 5 6 7 8 9 |
// 注意: 以下、CSSはすべてSCSSで書かれています。 html { font-size: 16px; @media (min-width: 800px) { font-size: 20px; } } |
あなたはこのコードを見てすぐに、800pxのビューポートにおいて16pxから20pxに変わることが分かると思います。これは適切な記述で、わたし達が長い間やってきたことです。
そして時には、2つのブレイクポイントを設定し、もう一つMedia Queriesの条件を加えなければならないこともあったはずです。
1 2 3 4 5 6 7 8 9 10 11 |
html { font-size: 16px; @media (min-width: 600px) { font-size: 18px; } @media (min-width: 800px) { font-size: 20px; } } |
多数のMedia Queriesに多数のフォントサイズを指定することは、もちろん可能ですが、これが3つ4つになると通常は過剰です。
しかし多数のMedia Queriesやフォントサイズを指定しないで、同じ効果が得られるならどうでしょう?
ここでビューポートの単位の登場です。フォントサイズのプロパティにビューポートの単位を使うことで、簡単に同じ効果を得ることができます。下記のコードを見てみてください。
1 |
html { font-size: 3vw; } |
フォントサイズ指定にビューポートを使用
ブラウザの幅の変化に対して、フォントサイズも変化します。
ここで指定した「3vw」は、320pxの幅(スマホ時)ではフォントサイズが10pxになってしまうので、読むのにはあまりにも小さいです。そして、1,440pxの幅(ラップトップ時)では43pxになり、今度は大きすぎます。
ビューポートの単位をフォントのサイズ指定に使う時には、もう一工夫が必要です。
この小さすぎる、大きすぎる問題を解決するシンプルな方法があります。
フォントのサイズに最小限をセットし、その上でcalc()プロパティを使って、小さいビューポートのフォントのサイズを調整します。コードを見てみましょう。
1 |
html { font-size: calc(18px + 0.25vw) } |
非常にシンプルなコードではありませんか?
このテクニックは「Precise control over responsive typography」で知りました。しかし同時に、このコードはいくつかのブラウザで機能しないことを悟りました。これはSafari for OS Xでは、サイズを変えません。
Safariにも対応させるのは、簡単です。
フォントの大きさを調整できるようにするには、最初の単位にpxではなく、%を使用し、vwと組み合わせます。
1 |
html { font-size: calc(112.5% + 0.5vw) } |
文字のサイズ指定に、%とvwを組み合わせた例
わたし達はこれでもう、Media Queriesとem, remをコードから削除することができるでしょうか? 私はこれから検証するのが楽しみです!
次のステップでは、よく使う見出し要素(h1-h6)のサイズをビューポートの単位でセットしてみます。
他の文字の要素をビューポートで指定
最初は本文の2倍の大きさで、h1要素のフォントサイズを作ってみます。ぱっと見、簡単そうですが、実はそうではありません。
まずhtml要素に指定した本文のサイズを2倍してみました。
1 2 |
html { font-size: calc(112.5% + 0.25vw) } h1 { font-size: calc((112.5% + 0.25vw) * 2); } |
上: 表示されたサイズ、下: 正しいサイズ
この指定方法だと、h1のサイズは期待通りになりませんでした。
原因は、%を使用してサイズを計算しているため、htmlで指定したサイズを継承し、h1でさらに計算し直しています。
ビューポートが800pxだとすると、デフォルトのフォントサイズは16pxです。
- htmlの「112.5%」は、「112.5/100 * 16px」で18pxになります。
- 「0.25vw」は、「800px * 0.25 ÷ 100」で2pxになります。
- htmlに指定したフォントのサイズは、「18px+2px」で「20px」になります。
h1のサイズを計算してみます。
- h1の「112.5%」は、「112.5/100 * 20px」で22.5pxになります。
- 「0.25vw」は、「800px * 0.25 ÷ 100」で2pxになります。
- h1に指定したフォントのサイズは、「(22.5px+2px)*2」で「49px」になります。
期待しているh1のサイズは本文の2倍、つまり40pxです。49pxではありません。この%で継承してしまったエラーを解決する2つの方法があります。
一つ目の方法は、h1の100%として112.5%をセットすることです。
1 |
h1 { font-size: calc((100% + 0.25vw) * 2) } |
二つ目の方法は、要素間で継承されないようにすることです。
1 2 |
h1 { font-size: calc((100% + 0.25vw) * 2) } p { font-size: calc((100% + 0.25vw)) } |
二つともあまりスマートな方法ではないので、私は満足せずに捜索し続けました。
最終的に私が見つけた最もクリーンな方法は、remとemを使うことでした。
1 2 |
html { font-size: calc(112.5% + 0.25vw) } h1 { font-size: 2em; } |
上: 表示されたサイズ、下: 正しいサイズ
期待通りのサイズで表示されました!
ここではフォントサイズを調整することについて話しているので、次にあなたが思う疑問は「縦方向のリズムやモジュラースケールはどうですか?」でしょう。
次のステップではそれについて話をしましょう。
縦のリズムとモジュラースケールをビューポートで指定
縦のリズムとは垂直方向の空白、モジュラースケールとは見出しや文章に使うフォントサイズをあらかじめ決定しておくことです。これは比較的答えることが容易です。
ここまででビューポートの単位は、html要素のサイズを決める時だけに使用していることに気がつきましたか? 他のすべてはremとemでサイズを指定します。
縦のリズムもモジュラースケールもremとemを使って、同じ方法で指定できます。
次にいく前に、一つアドバイス。
私が乗り越えなければならないもう一つのチャレンジがあります。
「ビューポートが800pxの時にフォントサイズを20pxにするためには、vwをどのように計算することができますか?」
ちょっと遠回しな言い方でした。質問を短くします。
「フォントサイズの指定の精度をアップすることはできますか?」
フォントサイズの指定の精度をアップする
私はこのチャレンジを解決しました。
どのように機能するか説明します。
-
- ビューポートが600pxの時
- フォントのサイズは、18pxになります。
-
- ビューポートが1,000pxの時
- フォントのサイズは、22pxになります。
まずはこの小さいサイズの18pxを%に変換します。
計算の最初の部分は次の通りです、「calc(18/16*100%)」もしくはシンプルに「calc(112.5%)」
次に、vwの量を計算します。
この計算は少し複雑です。
「フォントサイズ(22-18)」における差からvw値を計算し、「ビューポート幅(1,000-600)」における差で割り、その値に「100vw - smaller-viewport-width (100vw - 600px)」を掛けます。
コードすると、下記のようになります。
1 2 3 |
html { font-size: calc(112.5% + 4 * (100vw - 600px) / 400) } |
これは一見、複雑に見えるかもしれませんが、構成要素を理解していれば簡単です。このコードはSassのmixinでシンプルにすることができます。
上記ページのコードの唯一の変更点は、単位をpxではなく、%を使うことだけです。
さらに精度をアップする
もし異なるブレイクポイントで異なる比率で変わるフォントサイズを必要になった時、どのように実装すればよいでしょうか?
ここに一つの答えがあります。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
html { font-size: 100%; // 600pxから1,000pxまで、100pxごとに1px大きくなる @media (min-width: 600px) { font-size: calc(112.5% + 4 * (100vw - 600px) / 400) } // 1,000pxから2,000pxまで、100pxごとに0.5px大きくなる @media (min-width: 1000px) { font-size: calc(137.5% + 5 * (100vw - 1000px) / 1000) } } |
しかし、実際には異なる比率で大きくはならないでしょう。
実際には、下記のようにするのが現実的です。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
html { font-size: 100%; // 600px以降から、100pxごとに1px大きくなる @media (min-width: 600px) { font-size: calc(112.5% + 4 * (100vw - 600px) / 400) } // 1,000px以上は、22pxに @media (min-width: 1000px) { font-size: calc(137.5%) } } |
あなたが必要とするフォントのサイズ指定を達成するために、ビューポートの単位をMedia Queriesと組み合わせることはいくらでも可能です。
私は実際のプロジェクトにビューポートの単位を使うでしょうか?
その答えは「多分」です。私はまだ、結論をだすのに十分なほどビューポートの単位を仕事で使用していません。プロジェクトで使用する前に、する必要がある2つのポイントがあります。
- vwを計算するためのSassのmixinを作成する
- 各ブラウザのサポートとバグをテストする
もし本件についてあなたが知っているバグがあれば、ぜひ私に知らせてください。
まとめ
この論文では、フォントサイズの指定にビューポートの単位を使うことについて話しました。指定したサイズが自動的に計算し直されるため、ビューポートの単位はビューポートが変化する時はいつでも有益です。
実際に使用したところ、私はビューポートベースの単位はhtml要素にだけセットするのがもっとも良いことであることを見いだしました。他の要素には縦のリズムやモジュラースケールと同様にemとremでサイズを決められるはずです。
タイポグラフィのためにビューポートの単位を使うことについて、あなたはどう思いますか?
補足
GitHubやCodepen.ioにて、第三者による成果物もアップされています。
以下、元記事のコメントより。
sponsors