フォントのサイズ設定は役に立たない、問題点と解決方法
Post on:2021年4月13日
WebページやOSのUI、エディタなどのソフトウェアでフォントのサイズや行の高さを設定した際に起こる問題点と解決方法を紹介します。

Font size is useless; let's fix it
by Niki Tonsky
下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。
- はじめに
- フォントのサイズにおけるポイントとは
- emスクエアとは
- font sizeにおける問題点
- 解決方法
- line height(行の高さ)もめちゃくちゃです
- 予測が可能なline height(行の高さ)
- 終わりに
はじめに
あなたのお気に入りのエディタに、"font_size": 32を設定するとどうなりますか? お伝えしたいことがあるので、聞いてくれたら嬉しいです。
実際にやってみました。
私はmacOSでSublime Textを使っています。

Sublime Textに、"font_size": 32を設定
しかし、実際に文字を測定してみても、32という数字はどこにもありません。

文字のさまざまなサイズに、32はない
32は、文字の幅や高さではなく、大文字の高さ、小文字の高さ、アセンダーの高さ、ディセンダーの高さでもありません。これはどうしたものでしょうか?
フォントのサイズにおけるポイントとは
まず、そのサイズはピクセル単位ではなく、ポイント単位であるということです。ポイントとはタイポグラフィに由来する1/72インチ(0.353mm)に相当する物理的な単位です。
これは、スクリーンの解像度などの細かい条件を無視して、物理的な単位で直接フォントサイズを設定するという考え方です。文字の高さを2インチにしたければ、フォントサイズを144ptにすればいいのです。
しかし、実際には誰もそんなことはしません。その代わりに、macOSは常に72PPIを使用してポイントをピクセルに変換します。macOSを32インチモニターと24インチモニターの両方で解像度を1080pにすると、ピクセルサイズは同じになりますが、物理的なサイズは異なります。

サイズ指定は同じだけど、物理的なサイズは異なる
なぜ、72という数字なのでしょうか?
初代Macには、72PPIのディスプレイが搭載されていたそうです。そのディスプレイに文字を表示すると、スクリーン上の物理的なサイズは印刷時の物理的なサイズに一致します。便利ですね! もちろん、MacのディスプレイのPPIはその後改善されていますが、その慣習は残っています。
Windowsでは72ではなく、96PPIが採用されています。なぜ、72ではないのでしょうか? 表示が優れていたから(もしくはそうではなかったから)ではなく、72ではピクセルが少なすぎて読みやすいテキストをレンダリングできなかったのが理由です。そこで、1/3ほど大きくしてはどうかと考えました。
そして、彼らはその通りに実行したのです。72/3=24で、72+24=96になります。これは今でも続いています。Windowsの16ptのテキストは、macOSの16ptのテキストよりも1/3大きいのです。興味深いですね!

同じフォントを同じポイントサイズで表示
追伸: VS Codeではeditor.fontSizeの値を直接ピクセルで受け取るようです。これが始まりです。
emスクエアとは
つまり、32ptのフォントを要求しているユーザーは、実際にはmacOSでは32px、Windowsでは43pxを要求していることになります。しかし、これらの数字はまだどこにも見られません。
これは、フォントサイズがいわゆる「em」でサイズを設定するからです。
伝統的な金属活字では、emサイズは文字ピースの高さです。
なぜ、その高さを「em size(emサイズ)」と呼んだのか。「m」という文字が偶然にも正方形だったからで、「m」の幅==文字ピースの高さ==emサイズだったのです。シンプルですね!

デジタルの文字では、「em square(emスクエア)」は次のようになります。
デジタルフォントのデザイン空間として使用される、任意の解像度を持つグリッドのこと(ウィキペディアから引用)。
つまり、Fira Codeを開いてemスクエアを描いても、どこにも揃いません。

emスクエアはどこにも揃わない
簡単に言うと、この四角形はフォントサイズを設定する際に実際にコントロールするものです。フォントサイズを32ptに設定すると、四角形の高さ/幅は32/43ピクセルになります。残念ながらそれは不可視で、フォント内のどの要素にも一致しません。
font sizeにおける問題点
emサイズは完全に任意であり、フォントの内容とは全く関係がないと言っても、それは誇張ではありません。実際にそうなのです。
つまり、同じサイズに設定された異なるフォントでも、認識されるサイズが大幅に異なる可能性があります。例えば、2つの異なるフォントのemスクエア(==同じフォントサイズに設定されたもの)を並べると、「m」の高さが大きく異なります。

「m」の高さが大きく異なる
別の例を挙げましょう。
下記のフォントはすべて22ptで、同じサイズです。

すべて22ptのサイズ
フォントサイズについて、以下のような問題があります。
- 予測不可能: 何が得られるかを推測できません。16ptとは具体的に何ピクセルのことですか?
- 実用的ではない: 必要なものを手に入れることができません。フォントの高さを13ピクセルにしたいですか? できません。
- 安定していない: 他のフォントに変えると、同じサイズのままで、フォントが大きくなったり小さくなったりします。
- OSに依存する: 別のOSでドキュメントを開くと、異なるレンダリングになります。macOSとWindowsでエディタの設定を共有できません。
解決方法
- emスクエアのサイズではなく、キャップの高さを指定し、
- ピクセル単位で指定してください。
キャップは、人間の目が実際にテキストブロックの境界として認識するものです。そのため、他の任意に選択された指標ではなく、そのサイズを制御することが理にかなっています。

下記は、すべて同じフォントサイズに設定された複数のフォントです。

同じフォントサイズに設定された複数のフォント
こちらはすべて同じフォントですが、キャップの高さに合わせてサイズが変更されています。

キャップの高さに合わせたサイズに変更
私にとっては、後者の方が一貫性があります。例えば、CascadiaとConsolas。あるいは、HackとIBM Plex Mono。また、Ubuntu MonoとVictor Mono(最後の2つ)もそうです。
line height(行の高さ)もめちゃくちゃです
ついでに、line height(行の高さ)も修正しましょう。
心配しないでください、すぐです。
まず、各エディタで明らかにコンセンサスがありません。みながそれぞれのやり方でやっています。

なぜだと思いますか?
行の高さの問題は、同じ抽象的な文字の境界から計算されています。

文字の高さとデフォルトの行の高さ
この慣習は、金属活字では意味がありました。結局のところ、文字のボディよりも短い行を作ることはできません。

しかし、デジタルの文字では意味がありません。フォントサイズと同じように、文字の上下にある空きスペースの量は完全に任意です。
ある文字ではたくさんのスペースを確保します。そしてまたある文字では、アセンダとディセンダが収まる程度のスペースを確保します。

上下のスペースは任意
後者であっても、わたし達が望むものではありません。アセンダとディセンダは外れており、認識されるテキストボックスには影響しません。技術的にはもちろん、最小の行の高さは交差せずに両方に交差せずに収まる必要がありますが、審美的には最良の選択とは到底言えません。
フォントのデザイナーは文字の境界を自由に定義できるため、一貫した行の高さを取得しようとするのは推測ゲームになります。
予測が可能なline height(行の高さ)
どうすればいいのでしょう。
合理的な方法は、フォントのメトリックを無視して、行の高さをピクセル単位で直接設定することです。キャップの高さに対するパーセントで設定することもできますが、フォントサイズと同じにするのや「auto」にするのは絶対に避けてください。
もうひとつ重要なことは、行の高さを行間のスペースとして指定しないことです(金属活字ではリード)。そうしないと、2つの異なるフォントサイズで段落のリズムが崩れます。

行の高さを行間のスペースとして指定すると、段落のリズムが崩れる
その代わりに、ベースライン間の距離を使用する必要があります。

ベースライン間の距離を使用すると、段落のリズムは崩れない
また、いわゆる「デフォルトの行の高さ」を尊重する理由もありません。その値は基本的にフォントのデザイナーの個人的な好みなだけで、そのフォントを使用するすべてのユーザーのあらゆる表示条件に課せられます。したがって、どんな数字でも構いません。ただし、キャップハイトの200%は常に200%です。
結論を言うと これが現在の状況です。フォントを変更すると、行の高さがランダムになります。

line heightをautoにした場合
私が望むのは、下記です。
別のフォントに変更しても、すべての行は正確に元の位置に留まります。

line heightを16pxにした場合
これだけコンピュータが発達しているのに、フォントに関しては金属活字時代のフォントの癖がまだ残っているというのはおかしいですよね。
終わりに
ここでの提案で私が実現しようとしているのは、非常にシンプルな使用例です。
- 好みのフォントサイズと行の高さにエディタを設定するのは一度だけ。
- いろいろなフォントを試すことができる。
- そのたびに最初からフォントサイズと行の高さを設定し直す必要はない。
下記のように文字の高さと行の高さの両方が正確に一致します。

別のフォントに代わっても、文字と行の高さは同じ
これが私の夢のUIです。

2番目の使用例も非常にシンプルです。
ボタン内のテキストを中央に配置する、予測可能で信頼性の高い方法が必要です。
Webでは常に問題になっていましたが、最近ではmacOSでも問題になっています。

文字の高さが異なってしまう
Webページのレンダリングに使用されるフォントを常にコントロールできるわけではないので、テキストを確実に整列させるツールがないのは見落としているように思えます。
関連リンク
- Getting to the bottom of line height in Figma
Figma は、人々が求めるものとWebが実際に行うものとの間の妥協点を見つけることに成功しています。 - Deep dive CSS: font metrics, line-height and vertical-align
フォントとCSSのline-heightのアルゴリズムが具体的にどのように機能しているかを説明した素晴らしい記事です。 - Capsize
この記事で説明したことをWebの範囲内で正確に実行できるJSライブラリ。 - Leading-Trim: The Future of Digital Typesetting
leading-trimがあれば、フォントのサイズ設定がシンプルになります。
sponsors