等幅フォントが使われる要素の扱いがブラウザー間でまちまちな問題

少し前にFixing browsers’ broken monospace font handlingNice Web Type経由で読んだんだけど、「単純に初期設定が違うだけだろ……%指定すれば大丈夫じゃね?」とか高をくくってたら大間違いだった。font-size: 100%がうまく動かなかったり、pre要素はともかくcode要素辺りでの実装のずれとか、monospaceだけだとWebKitでおかしくなるバグとかも絡んできてかなりの魔窟のようだ。この記事では触れられていないけど、言語設定によって等幅フォントの初期サイズが違うこともあるので更なるカオス。

記事で最初に挙げられているコードでも良いのだけど、normalize.cssではこの問題への対処がちゃんとなされているので、細かいことは余り考えずにnormalize.css使うのが手っ取り早い。記事の最後に挙げられているコードのように、ラテン系の言語に設定されているブラウザーでの挙動(等幅フォントを1段階小さいフォント・サイズにする)に合わせる場合は、normalize.cssのコードも混ぜた上である程度ネストへも対処するように書く必要がある。

html {
  font-size: 100%;
}

pre,
code,
var,
samp,
kbd,
tt {
  font-family: monospace, serif;
  _font-family: 'courier new', monospace;
  font-size: 0.8125em;
}

pre code,
pre var,
pre samp,
pre kbd,
pre tt {
  font-size: 100%;
}

rem単位さえ使えれば……という感じだ。と、対処を書いた所でどういう問題があって、どうすれば解決でき、なぜ今まであまり表面化しなかったのかということをちょっと書く。

存在する問題

問題はだいたい以下の4つに分けることができる。

素のpre要素
初期サイズはブラウザー間で殆ど差はないと言って良い。ので、このまま何もいじらないならあまり問題は起きない……わけだが、ユーザー設定と言語設定により結構な差があるのでやはり少しはいじりたい。
font-size: 100%
地の文とフォント・サイズを合わせる目的で指定するわけだが、Internet Explorer 9とOpera 11でしか期待通りに動かない。どうもFirefox 10やChrome 17、Safari 5ではフォント・ファミリーを指定してやらないとfont-sizeプロパティーによるサイズ指定が有効にならないようだ。
font-family: monospace
フォント・ファミリーを指定する場合も1つだけではダメで、monospace, serifなどもう1つ必要。normalize.cssでserifが使われているのは単にジェネリック・ネームの中で一番短いからだと思う。
code要素他
code要素など等幅フォントで表示される他のインライン要素でも似たような問題が発生する。こちらはpre要素にネストされることがあるので更に厄介。親でのem単位でのフォント・サイズ指定を継承するかどうかという点でIE9/Op11陣営とFx10/Ch17/Sf5陣営の間に壁があり簡単には統一できない。

解決するための条件

現時点では以下の3つの条件が統一のために必須ということになりそう。

  1. ユーザー設定や言語設定の違いを吸収するためにfont-sizeを指定する
  2. Firefox 10とChrome 17、Safari 5のためにfont-familyプロパティーで二種類以上指定する
  3. 親要素でのfont-sizeプロパティーの値としてem単位を使わず%単位を使用する

で、上記コードのような形になるわけ。

問題が表面化しない理由

多くの場合body要素でベースとなるフォント・サイズを指定し、preを始めh1要素などあらゆる要素でそれに対する相対的な値(%em)を使うことが多い。ベースとなるフォント・サイズは慣例的に%pxを使う人が多く、かなりの確率で条件3はクリアされる。ジェネリック・ネームのみでフォント・ファミリーを指定する人はまずいないので、条件2でハマることはまずないだろう。

問題になるのは条件1で、これはフォント・サイズを指定するかどうかにかかっており、ここでハマる可能性はかなり高い。が、そもそもこのバグがうまくフォント・サイズが反映されないというバグなので、指定しない場合はこの問題は発生しているが表面化しない。


僕の場合は長らくYUI CSS Fontsを使っていたというのが、この問題に対して無知だった理由だと思う。YUI CSS Fontsを使うだけで条件1と3はクリアできるので、上記CSSコードを自分なりに書き換えて使っても良いけど、YUI CSS Fontsでも事足りる。YUI CSS Fontsはちょっとな……というのならnormalize.cssがお手軽かつ無難。