line-height の計算式をアップデートしたのでその解説

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-height1.8
  • 文字サイズが大きくなるほど line-height を小さくする。
  • 最大の文字サイズ(既定値が 8 なので 8rem が最大になる)のときの line-height1.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 も動的に変化するようにしたりしているので実際にはもう少し複雑なコードになっていますが、おおよそこんな感じで設計しています。

もっとコード最適化できそうとか、自分はこういうやり方しているよ、などありましたら、ぜひ教えてください!

inc2734のアバター

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です