画面サイズを変化させた時のフォントサイズの挙動について考えつつも、後回しにていたのですが、twitterで以下の記事が目に止まったのでこれを気に勉強しようと思いました。
[CSS]レスポンシブ用にフォントのサイズと行の高さを可変で指定する極上テクニック -The math of CSS locks
ですが私は、数学がすごく得意なわけではないので理解度が足りないせいか、結局どうすればいいかわからないという状態になってしまいました。
そこで、一度自力で考えてみると、解決できたのでその内容を備忘録もかねて書きます。
同じように、上記のサイトを見ても結局どうすればいいかわからないという方の参考になれば幸いです。
デモ
ゴールを確認する
今回行いたいこと
上記の画像のように、例えば
画面サイズ320px〜960pxの間を画面サイズに比例してフォントサイズを変更したい。
画面サイズ0px〜319pxまではフォントサイズを20px、画面サイズ961px以上はフォントサイズ40pxしにたい。
このように
- ある画面幅〜ある画面幅の間で画面サイズに比例してフォントサイズが変更されるようにしたい
- 上記の画面幅以外の画面幅の場合は指定したフォントサイズにしたい
という条件を満たすcssを書くことが今回のゴールとなります。
vwではだめなのか
画面幅に合わせて数字を変化させる方法といえばvwという単位を使って画面幅の○○%という形で変化させることもできますが、vwを使用すると今回目指す動きとは少し異なる動きをしてしまいます。
vwでfont-sizeを設定した場合のデモ
このようにフォントサイズの切り替わりの際にガタツキが出てしまいます。今回はこのガタツキをなくし、滑らかにサイズが変わるcssの書き方を考えます。
画面サイズに比例してフォントサイズを変化させてみる
まず、ある一定の範囲ないで画面サイズに比例してフォントサイズを変化させる方法を考えてみます。
ここでは比例する割合を求めなければいけません。
ですので、Xの変化量/Yの変化量となります。
よって①の式:(40 – 20)/(960 – 320)となります。
こちらのフォントサイズの挙動を一度見てみましょう。
この変化量の割合に現在の画面サイズを掛けるとフォントサイズを求めることができます。
赤の線が目指すべき値なのですが、真ん中の部分のフォントサイズが小さくなってしまっています。
この差分を埋めればゴールと同じ挙動になりそうですね。
では、この差分を求めるにはどうしたらいいでしょう。
画面幅960px地点でのフォントサイズ40pxから青線上の960px地点でのフォントサイズ30pxを引けば出てきそうです。
40-30になりますが、そもそも、30を求める式を求めなければいけません。
ですので、30の部分を求める式は
②の式:40 – (40 – 20)/(960 – 320) * 960
となります。
そして差分を埋めなければいけないので①の式と②の式を足し合わせます。
③の式:((40 – 20)/(960 – 320) * 現在の画面幅) + (40 – (40 – 20)/(960 – 320) * 960)
これの挙動を見てみましょう。
見事一致しました。
現在は具体的な数字を入れていますが、これを変数へ置き換え値を変更しても対応できるようにします。
min_size:フォントサイズの最小値
max_size:フォントサイズの最大値
min_mq:メディアクエリの最小値
max_mq:メディアクエリの最大値
now_display:現在の画面幅
④の式:(((max_size – min_size) / (max_mq – min_mq))*now_display)+(max_size – (((max_size – min_size)/(max_mq – min_mq))*max_mq))
となります。
オリジナルの式と先のサイトの式を見比べてみる
先のサイトでは変数への変換をしておらず③のような式で完結しています。
1.5rem + ((40 – 24) / (960 – 320)) * 100vw – ((40 – 24) / (960 – 320)) * 320px
これを変数に変換してみました。
⑤の式:min_size + ((max_size – min_size) / (max_mq – min_mq)) * now_disply – ((max_size – min_size) / (max_mq – min_mq)) * min_mq
ん? ④の式と、⑤の式の違いって
- max_size → min_size
- max_mq → min_mq
これだけ。 これは②の式の差分を埋める部分の参照が下の画像の赤枠から青枠に変化しただけ。
グラフから見てもわかる通り、どちらで計算しても同じなので、結果的に同じ答えに行きついたということになります。 先のサイトには簡略化した式が掲載されていました。
1.5rem + 16 * (100vw – 320px) / (960 – 320)
これを元に自分の式も簡略化して見ました。
するとこちらの式が完成しました。
max_size + (max_size – min_size) * (now_disply – max_mq) / (max_mq – min_mq)
これを先サイトの式と合わせてグラフに描画して見ます。
同じになりました。 完成したコードを実際に実行してみましょう。 scss
$minSize:20; $maxSize:40; $minMq:320; $maxMq:960; font-size: calc(#{$minSize} + ((#{$maxSize} - #{$minSize}) * (100vw - #{$minMq}) / (#{$maxMq} - #{$minMq})));
実行してみるとわかるのですが、実はこれ動きません。
その理由はcalcの書き方にあります。
calcには単位の付け方にルールがあり、この場合は以下の部分にpxを付けなければなりません。
font-size: calc(#{$minSize} + ((#{$maxSize} - #{$minSize}) * (100vw - #{$minMq}) / (#{$maxMq} - #{$minMq}))); ____________________↑______________________________________________________↑
ですが、minSize/minMqはどちらも別の箇所で使用するので新しく変数を用意して単位を付けたものを用意しなければなりません。単位をつける箇所はこちらの2箇所のみで、他の箇所に付けてしまうとエラーとなります。ですので 変数を用意して単位を付けます。
$minSize:20; $maxSize:40; $minMq:320; $maxMq:960; $minSizePX: #{$minSize}px;//←単位をつける $minMqPX: #{$minMq}px;//←単位をつける font-size: calc(#{$minSizePX} + ((#{$maxSize} - #{$minSize}) * (100vw - #{$minMqPX}) / (#{$maxMq} - #{$minMq})));
フォントサイズはよく使用するのでmixinでまとめ、簡単に使用できるようにしましょう。
@mixin flexFontSize($minSize, $maxSize, $minMq, $maxMq) { $minSizePX: #{$minSize}px; $minMqPX: #{$minMq}px; font-size: calc(#{$minSizePX} + ((#{$maxSize} - #{$minSize}) * (100vw - #{$minMqPX}) / (#{$maxMq} - #{$minMq}))); }
以下のように呼び出すことで使用できます。
.hoge{ font-size:40px; } @media screen and (min-width:320px) { .hoge{ @include flexFontSize(40,80,320,960); } } @media screen and (min-width:960px) { .hoge{ font-size:80px; } }
calcの単位の付け方は書いた式の内容によって変わるのですが、かなりわかりにくいですし、そのルールについて記載しているサイトが少ない状況です。
calcのルールについてこちらにまとめました。
calcの計算式のルールと使い方。calcが動かない時の対処法はこれ
まとめ
下記のcssで実装することができます。
@mixin flexFontSize($minSize, $maxSize, $minMq, $maxMq) { $minSizePX: #{$minSize}px; $minMqPX: #{$minMq}px; font-size: calc(#{$minSizePX} + ((#{$maxSize} - #{$minSize}) * (100vw - #{$minMqPX}) / (#{$maxMq} - #{$minMq}))); }
実際にフォントサイズを計算している部分は以下です
calc(#{$minSizePX} + ((#{$maxSize} - #{$minSize}) * (100vw - #{$minMqPX}) / (#{$maxMq} - #{$minMq})))
使用方法です
@include flexFontSize(フォントサイズmin,フォントサイズmax,画面サイズmin,画面サイズmax);
メディアクエリを忘れずに