この記事は Snow Monkey / unitone Advent Calendar 2024 9日目の記事です。まだまだ空きがたくさんあるので、ぜひお気軽にご参加ください!
unitone v15.5.0 で line-height
の計算式をアップデートしたのでその解説を書きたいと思います。
まずは文字サイズの実装について
unitone では、調和のとれた文字サイズのバリエーションを定義するために、調和数列を用いて文字サイズを算出しています。
調和数列とは…
逆数が等差数列である数列のこと。例えば、1/2, 1/3, 1/4 は逆数が 2, 3, 4 であり、差が1の等差数列になるので、この数列は調和数列となる。
分子が1の調和数列だと文字サイズがすごく小さくなってしまうので既定値 8
を掛け、そして分母を1
ずつ減らしていってバリエーションをつくっています。
8 / (8 - 0) なら 1。つまり 1rem。
8 / (8 - 1) なら 約1.14。つまり 1.14rem。
...中略...
8 / (8 - 7) なら 8。つまり 8rem。
これを下記の CSS で実装しています(わかりやすくするために実際とは異なる改変をしています)。
:root {
--unitone--font-size: 0;
--unitone--harmonic-sequence-base: 8;
}
$font-size-scale: calc(var(--unitone--harmonic-sequence-base) / (var(--unitone--harmonic-sequence-base) - var(--unitone--font-size)));
* {
font-size: calc(#{ $font-size-scale } * 1rem);
}
これで下記のようにすると調和数列に沿って調和の取れた文字サイズを指定できます。
<p style="--unitone--font-size: 1">ここは約1.14rem</p>
<p style="--unitone--font-size: 7">ここは約8rem</p>
line-height の実装
そして肝心の line-height
の実装について。上記で、文字サイズは --unitone--font-size
を指定して算出できることを示しましたが「文字サイズを指定するたびにその文字サイズに最適な line-height
も指定するのは面倒なので、文字サイズを指定すればその文字サイズに最適な line-height
も自動的に反映されるようにしたい」と考えました。
じゃあその最適な line-height
はどうやって算出するのかという計算式が必要になるので、unitone では下記の計算式を用いることにしました。
- 基本の
line-height
は1.8
。 - 文字サイズが大きくなるほど
line-height
を小さくする。 - 最大の文字サイズ(既定値が
8
なので8rem
が最大になる)のときのline-height
は1.1
になるようにする。
これを数式にすると下記になります。
{line-height} = -0.1 * {文字サイズの倍率(つまり何remか)} + 1.9;
そして下記のように実装しました(わかりやすくするために実際とは異なる改変をしています)。
:root {
--unitone--half-leading: .4;
}
$min-line-height: 1.1;
$max-line-height: calc(1 + 2 * var(--unitone--half-leading));
$line-height-slope: calc((#{ $min-line-height } - (#{ $max-line-height })) / (var(--unitone--harmonic-sequence-base) - 1));
$line-height-intercept: calc(#{ $max-line-height } + -1 * #{ $line-height-slope });
// line-height が大きくなりすぎたり小さくなりすぎないように、clump() を使って 1.1 〜 1.8 に収まるようにする。
$line-height: clamp(
#{ $min-line-height },
#{ $line-height-slope } * #{ $_font-size-scale } + #{ $line-height-intercept },
#{ $max-line-height }
);
* {
line-height: #{ $line-height };
}
問題点
おおよそこれで良い感じにできたと思ってこれまでやってきてたのですが、ふと以下のことが気になりました。
- 文字の最大サイズ(現状
8rem
)のときに1.1
になるのが最適としているけど、規定をカスタマイズして10
としたら、10rem
のときに1.1
となる。でも本当は8rem
の段階で1.1
になって欲しくね? - そもそも
5rem
くらいで1.1
になったほうが読みやすくね? --unitone--half-leading
もカスタマイズ可能なので、例えば--unitone--half-leading: 0
にしたら最大のline-height
が最小のline-height
である1.1
を超えちゃうからあべこべになるよね?
アップデートでどう変えたか
上記の問題点を解決するために、下記の変更をおこないました。
- 最大の文字サイズのときに最小の
line-height
になるようにしていたのを、もっと早い段階で最小になるように変更(固定で5rem
にしちゃってるので、ここもカスタマイズ可能にするかは今後要検討)。 - 基本の
line-height
は--unitone--half-leading
を上書きすることでカスタマイズできたが最小のline-height
が固定になってしまっていたので、--unitone--min-half-leading
を追加して最小値もカスタマイズできるように変更 - 最小の
line-height
が基本のline-height
を超えることがないようにmin()
を使って調整
CSS 的にはこんな感じ。
:root {
--unitone--half-leading: .4;
--unitone--min-half-leading: .1;
}
$min-line-height: calc(1 + 2 * min(var(--unitone--min-half-leading), var(--unitone--half-leading)));
$max-line-height: calc(1 + 2 * var(--unitone--half-leading));
$max-line-height-target-font-size-ratio: 5;
$line-height-slope: calc((#{ $min-line-height } - (#{ $max-line-height })) / (#{ $max-line-height-target-font-size-ratio - 1 }));
$line-height-intercept: calc(#{ $max-line-height } - #{ $line-height-slope });
// line-height が大きくなりすぎたり小さくなりすぎないように、clump() を使って 1.2 〜 1.8 に収まるようにする。
$line-height: clamp(
#{ $min-line-height },
#{ $line-height-slope } * #{ $_font-size-scale } + #{ $line-height-intercept },
#{ $max-line-height }
);
* {
line-height: #{ $line-height };
}
流体タイポグラフィ(画面幅に応じて文字サイズが変化する)時に、文字サイズの変化にあわせて line-height
も動的に変化するようにしたりしているので実際にはもう少し複雑なコードになっていますが、おおよそこんな感じで設計しています。
もっとコード最適化できそうとか、自分はこういうやり方しているよ、などありましたら、ぜひ教えてください!
コメントを残す