安全な@font-faceの書き方(抄訳)

Internet Explorerではかなり昔からあった埋め込みフォント(@font-faceによるフォントの参照)の機能は、Safari 3とFirefox 3.5で有効になったことから急速に話題になることが増えた。ようやく時代がMicrosoftに追いついてきた感じですね。その書き方は大筋では一緒なのだが、細かな仕様の違い、というかIEがEmbedded OpenTypeしかサポートしていないことから工夫が必要になる。その工夫をBulletproof、つまり将来にわたって安全であろうという観点で短くまとめたBulletproof @font-face syntaxというすごく参考になったエントリがあったので訳しておく。語調などは超訳なので、原文とニュアンスが変わっているかもしれない。

Bulletproof @font-face syntax

最も優れた@font-faceの定義方法を解説させて貰おう:

@font-face {
  font-family: 'Graublau Web';
  src: url(GraublauWeb.eot);
  src: local('Graublau Web Regular'), local('Graublau Web'),
         url(GraublauWeb.otf) format('opentype');
}

最後になぜこの方法が最も優れたものなのかは説明することにして、最初に他の方法の欠点を解説することにしたい。もちろん、問題の中心になるのはIEが.eotフォントが必要なのに対して、他のブラウザでは.ttfか.otfを必要とすることである。それでは順に解説していこう。

条件付コメントによる方法

<style type="text/css" media="screen">
@font-face{
  font-family:'Graublau Web';
  src: url('GraublauWeb.otf') format('opentype');
}
</style>
<!--[if IE]>
<style type="text/css" media="screen">
@font-face{
  font-family:'Graublau Web';
  src: url('GraublauWeb.eot');
}
</style>
<![endif]-->

本気なのだろうか?ありとあらゆるHTMLファイルにこのコードを挿入するか、iefont.cssというファイルを作成して参照させなくてはならない。面倒で、美しくない。

二重に定義する方法

@font-face{
  font-family:'Graublau Web';
  src: url('GraublauWeb.eot'); /* here you go, IE */
}
@font-face{
  font-family:'Graublau Web';
  src: url('GraublauWeb.otf'); /* everyone else take this */
}

Andreaが指摘したこの方法の問題点はIEが.otfファイルをダウンロードしてしまうことだ。無駄なHTTP接続が発生させることは許されない。この問題に対するよくある対処はこうなる:

@font-face { 
  font-family: 'Graublau Web';
  src: url('GraublauWeb.otf') format('opentype'); /* IE no comprende format()! */
}

知っていると思うが、IEはformat()を解釈できない。ではそこで何が起こるかというと、IEは以下のようなファイルをリクエストする:

GraublauWeb.otf')%20format('opentype

これは……正規表現で?を使うの忘れたようだ。しかし、20から100 KBのファイルをダウンロードさせるよりは404の方がまだマシではある。それでは404をどうにかしてみよう:

もっと安全な方法

@font-face{
  font-family:'Graublau Web';
  src: url('GraublauWeb.eot'); /* here you go, IE */
}
@font-face{
  font-family:'Graublau Web';
  src: url(//:) format ('no404'), url('GraublauWeb.otf'); /* tricky! */
}

このエントリに対してRichard Finkが別の書き方を提示してくれたので、ここに追記しておく。その方法はurl(//:)を利用して、IEが404になるようなリクエストをさせなくするものだ。彼のエントリにはこの書き方を利用する理由を理論付けている。その主張は理解できるが、自分では利用したいとは思えない。

ローカルへの参照を利用する方法

@font-face {
  font-family: 'Graublau Web';
  src: url(GraublauWeb.eot);
  src: local('Graublau Web Regular'), url(GraublauWeb.otf) format('opentype');
}

かなり簡潔で明瞭だ。IE以外のブラウザは.eotファイルを飛ばし次の定義を参照する。一方、IEは二番目の定義を解釈しようとするが、local()によるファイルの場所の指定を理解できない上に、複数のファイルの場所の指定も理解できない。ということで.eotファイルを参照することになる。IEは必ず最後のsrc: url()を参照することになるので、この方法はうまく動作しないだろう

src: url(GraublauWeb.eot);  
src: url(GraublauWeb.otf); /* Yeah IE will only try this one. :( */

また他の利点として、もしユーザー(訳注: サイトの訪問者)がカスタム・フォントをインストールしていた場合、ダウンロードさせないで済むことになる点が挙げられる。注意点としては、OS X上のSafariは完全なフォント名ではなくPostscriptフォント名のみを受け付けるので、両者が違う場合は両方含めて記述しなければならない:

安全な@font-faceな書き方

@font-face {
  font-family: 'Graublau Web';
  src: url(GraublauWeb.eot);
  src: local('Graublau Web Regular'), local('Graublau Web'),
         url(GraublauWeb.otf) format('opentype');
}

補足その他:

  • font-variantプロパティを定義に含めてしまうと、IE 6-8やSafari(4.0.3で確認)では動作しない(Thanks Sid)。
  • font-styleプロパティを定義に含めても安全で全てのブラウザで正常に動作するが、IEはその値を無視する。
  • Operaはlocal()の値を引用符で括らないと参照に失敗する。なので、こう書く: local('Use Quotes')。仕様の違反としてOperaにバグ報告をした。Scott KinlerRichard FinkのOperaの適切でない振る舞いに対する根気強い調査に感謝する。
  • Safariのパーミッションエラー?local('Fontin')というように使った場合、もしユーザーがローカルにFontinをインストールしていた場合、セキュリティの警告ダイアログでそのファイルの使用の許可を求められる、というような報告があった。まだこの挙動について返答することはできない。しかし、私がテストしたところでは、すべてのブラウザがローカルのフォントを利用するわけではないようだ: Opera 10 (Win XP)とSafari 4 (Win XP)は参照しないが、Fx 3.5 (Win & OS X)とSafari 4 (OS X)はちゃんと利用してくれる。
  • Chrome?Chromeのベータ版またはdevビルドで@font-faceがサポートされたという噂はある。この機能はインストール時に有効になっていないが、Chrome 3のコマンドライン・オプションで指定することによって有効にできる。私はこのブラウザのサポート状況を詳細と共に最新の状態に更新している。
  • FxやOpera、Safariに対してTruTypeフォントを提供することもできるが、その場合もformat('opentype')と指定すると良いだろう。提供するフォントがOpenTypeとTrueTypeのどちらであろうとも、フォーマットのヒントは必須ではない。
  • クロスブラウザのテスト用にテストページを作成した: http://dl.getdropbox.com/u/39519/webfontsdemo/index.html

以下は訳注と私見。

条件付コメント

面倒くさいというのはわからなくもないけど、実際はCMSなりなんなりのテンプレートをさくさく書き換えるだけな場合が多いと思うので、そんなでもないような気もするし、将来に渡って安全という観点では条件付きコメントは最も優れているような気がする。その一方で条件付コメントがとにかく受け付けないという何かを持っている人が多いことも理解できないことはない、というかどっちかというとそっち側の人間なのでこの方法を採用したくない気持ちもわかる。

url(//:)...

これで404になるリクエストが発生しない理由は、上の例だと、

//:) format%20('no404'),%20url('GraublauWeb.otf

というURLをリクエストするので、そのウェブページのドメインに対するリクエストではなくなるから。IEからは404に見えるのは変わらない。

format('opentype')をTrueTypeでも指定する

これの意味がわからない。現状ではどちらでも変わらないのだけど将来は変わるかもしれないと思う。というかOSに依存するのだろうけど変わるんじゃないかと思う。とは言うもののTrueTypeを提供して format('truetype')を指定する際に何かしらの問題点はあるかもしれないので、それはオススメできなとは思う。のでOpenTypeを提供するのが現状では無難でかつBulletproofな気がする。


埋め込みフォントを日本語フォントで……となると、個人のサイトではサイズや帯域の面でも労力やコストの面でもなかなか難しいけど、金に糸目をつけない規模の大きなサイトでなら浸透する可能性はあるのかな。

Bulletproof的なアプローチの話は話題になること自体少なかった(あってもごく一時的だった)けど、優秀なモダンブラウザが増えてきて新しい表現を方法をウェブが手に入れる一方で、いまだにIE6を使っている昭和な人が無視できない数存在することから、今ではウェブデザインにおいて最も力を入れて考慮すべきことになった気がする。クロスブラウザではなくエラスティック・ウェブデザインみたいな意味で。

とかいうとりあえず言ってみました的な言葉で締める。Bulletproofを「将来に渡って安全な」とか訳すと堅苦しいのでなんか良い訳が欲しいな。