CSSでフォントサイズの変数名にSI接頭辞を使ってみたらどうだろう

これは今に始まったことじゃないですが、JSにしろCSSにしろ、変数名ってめちゃくちゃ悩むんですよね。

今日はCSSのフォントサイズを変数化する際にSI接頭辞を使ってみたらどうだろうか、という提案をさせていただきたい。

フォントサイズの値の特徴として、下記のようなものがあると思います

  • 数値型
  • 基準となる値があり、それより小さいものと大きいものに分けられる
  • 値そのものより、他の値より大きいのか小さいのかが重要(イメージできるので)
  • せいぜい5〜8種類程度になるはず

要するに 数値型で相対的な大きさがなんとなく想像できるような変数名 だと良い変数だと思うわけです。

そこでこちらをご覧ください

$font-size-micro: 12px;
$font-size-milli: 14px;
$font-size-base: 16px;
$font-size-kilo: 18px;
$font-size-mega: 24px;
$font-size-giga: 32px;

基準である16pxをベースに、それより小さいものをミリやマイクロ、大きいものをキロ・メガ・ギガとすることで、相対的な大きさを想像することができる変数名とすることができたと思います

試しにこの変数名を、あえて分かりにくいセレクタで使ってみるとこんな感じになります。

.headline {
  font-size: $font-size-kilo;
}
.date {
  font-size: $font-size-milli;
}
.value {
  font-size: $font-size-giga;
}

フォントサイズの大小が明確になるだけで、随分と要素の重要度がCSSを見ただけで伝わるのではないかと思うわけです。

しかも、この程度のSI接頭辞ならエンジニアではなくても、なんなら小学生でも直感的にわかるという嬉しさ。

中間サイズの追加に弱いという欠点はあるものの、デザインシステムがカチッとしている状況であれば、十分使えるのではないでしょうか。


ちなみに、これを考えているときに思いついた別案ですが、むしろ日本語で曖昧な変数名作っちゃえばもっとわかりやすくて汎用的になるのではと思ったりしました

$font-size-結構小さい: 12px;
$font-size-ちょっと小さい: 14px;
$font-size-基準: 16px;
$font-size-ちょっとデカい: 18px;
$font-size-まあまあデカい: 24px;
$font-size-相当なデカさ: 32px;
$font-size-アホほどデカい: 64px;

これなら中間サイズが追加されても表現次第でどうにでもなるので最強です。優れたエディタなら補完もしてくれるので表記ゆれなんて気にしなくて良い。日本語すごい!

文字を思い通りの大きさと位置で表示するCSS

基本的に文字というものは、大文字・小文字など文字の種類によって目に見える大きさ(高さ)が異なります。

例えばCSSで font-size を100pxに指定した場合でも、文字がピッタリ100pxで表示されるわけではありません。

これをCSSで思い通りに指定する方法を調べてみました。

(欧文フォントの場合)

欧文フォントの基礎知識

アルファベットでは、文字の下端( y などの下に飛び出る小文字を除く)となるベースラインを基準に、デザイン上の指標となる高さがいくつか存在します。

  • アセンダ:ベースラインから bd など小文字で上に飛び出る部分の上端までの距離
  • ディセンダ:ベースラインから jy など下に飛び出る文字の下端までの距離
  • エックスハイト:ベースラインから x など、小文字の上端までの距離
  • キャップハイト:ベースラインから大文字の上端までの距離。アセンダより少し下に位置することが多い

※こちらの図がわかりやすいです http://w3.kcua.ac.jp/~fujiwara/infosci/font.html

例えば Arial のメタデータを解析してみると、下記の値を発見できます

  • ascender: 1854
  • descender: 434
  • sxHeight: 1062
  • sCapHeight: 1467

数字の大小はさておき、これらの値でまず意識しなければならないのは単位です。

実はこの数字、単位はピクセルでもミリメートルでもありません。
各フォントが em-square という基準値を決め、それに対する相対値として定義されています。

これもメタデータを見てみると発見できます

  • unitsPerEm: 2048

要するに Arial の場合は、2048を基準に、それよりどのくらい大きいのか、小さいのか、という相対的な数字なのです

文字サイズ16pxのxの大きさ

そしてこの em-square こそがCSSの font-size と直接関わってくる部分。

例えば font-size: 16px; とする場合、xの高さは

var xHeight = (1062 / 2048) * 16px

約8.3pxとなります。

また、逆算的にキャップハイトが100pxになるためのfont-sizeは

var fontSize = 100px / (1467 / 2048)

約139.6pxになります。

font-size は、実は スケール感をふんわり指定しているだけ で、必ずしもその大きさで文字が表示されるわけではない、ということが分かって頂けたかと思います。

文字の表示位置とline-height

ここまでで表示したい大きさのfont-sizeは見いだせるようになったと思いますが、実際にこれをウェブのレイアウトで使うためには、表示位置も制御できねば意味がありません。

em-squareascender などの値はあくまで距離の数値なので、そのまま位置算出に使うことはできなさそうです。

CSSでインライン要素の表示位置といえば vertical-align ですが、これはベースラインを揃えたりなど、わりとアバウトな配置の指示しかできませんし、 line-height の設定値次第で文字の表示位置は大きく変わります。

line-height に関して言えば、実はデフォルト値である normal は、下記の計算式で算出されているみたいです

var lineHeight = (ascender + descender + lineGap) / unitsPerEm

lineGap は、他の値と同じようにフォントのメタデータとして記録されていて、例えばArialは 67 です。フォントによっては0なこともあります。

ascender + descender が文字の表示しうる範囲ですが、lineGapはその半分の数値がascenderの上とdescenderの下に割り振られるような表示になります。

上記の式をArialのメタデータで計算してみると、結果は 1.1499 になります。約1.15です。

実際に下記のようなCSSを使ってp要素の高さをDevToolsで見てみると、115pxになってるのが確認できるはずです。

p {
  font-family: 'Arial';
  font-size: 100px;
  line-height: normal;
}

ということは、 line-height: normal を指定してJSで高さを取得し、他のメタデータからBaselineの位置を算出することで最終的にはCapHeightやxHeightなどの表示位置も計算できるはずです。

var baselineY = lineHeight - (lineGap / 2 + descender) / unitsPerEm
var xHeightY = baselineY - sxHeight / unitsPerEm
var capHeightY = baselineY - sCapHeight / unitsPerEm

結論は、CSSでフォントを深く掘るのはつらいということです