BLOG



この記事の最初の公開後、さらに調査を続けていたところ、内容に不正確な部分があることがわかりましたので、訂正いたしました。詳細は本文中の追記・訂正をご覧ください。(2010/06/01)

こんにちは。フロントエンド担当、松島です。

先日、Google から、画期的なウェブフォントサービスの Google Font API が発表されました。既にたくさんの方々が、様々な実験をしたり記事を書いたりいらっしゃいますが、そんな昨日。

「Google Font API で日本語が表示出来ない」という話を小耳に挟みました。

» Togetter - まとめ「あなたのサイト大丈夫ですか...?」

(Twitter で流れていたこの話題を、弊社の守谷がまとめてくれました。現象をひろく公開してくださった @tacamy さんに御礼申し上げます。

もとより、Google Font API で提供されるフォントは現時点では欧文フォントのみで、日本語の字形データは含んでいませんが、仮にそうしたフォントが日本語を含む文字列に指定されたとしても、本来そこで期待されるのは「指定フォントで表示できない文字は、表示できる別のフォントで表示する」という挙動であって、真っ白になってしまうのは困ります。

このように別フォントで表示するという挙動がブラウザに期待される旨は、W3C勧告の仕様書にも明記されています(CSS 1 / CSS 2.1 / CSS 3 案)。

(追記)ただし、これはあくまで、指定フォント内にその文字のを扱う方法がまったく示されていない場合の話である、という条件のもとに語られるべき事柄かもしれません。

今回、問題が起きているのが iPhone / iPad の Safari である、というところで、思い当たることがありました。検証してみたところ、事情が把握できましたので、皆さんと共有したいと思います。

(追記)当初この記事に書いた内容に誤りがありましたので、訂正して再度公開いたします。

この記事を書いている時点でこの問題に遭遇されているような方の多くには必要ないような基本的なことがらも、将来のために敢えて解説してみました。冗長に感じられる方もいらっしゃると思いますが、適宜読み飛ばしていただければ幸いです。


Google Font API は @font-face を利用する

Google Font API は、CSS 3 の @font-face を利用しています。@font-face は、外部にファイル化されたフォントデータを読み込んでおき、ウェブページを表示する際、ユーザのマシンにインストールされたフォントと同様に扱えるようにする技術です。

この @font-face で指定できるフォントには様々な種類があります。まず、徐々にウェブフォントフォーマットとしての標準化が進んでいる WOFF (Web Open Font Format) や、それよりはなじみ深い OTF (OpenType Font) や TTF (TrueType Font)、Internet Explorer に採用されている EOT (Embeded OpenType) など、フォント専用のフォーマットに納められた、いわゆる一般的なフォントファイルの系統が利用できます。

その他に、文字ひとつひとつの字形を、SVG という XML テキストデータで表現した SVG フォントも使うことができるのですが、今回の問題は、この SVG フォントに対するブラウザの振る舞いが理由で起きています。

Google Font API は ブラウザごとに異なる CSS / フォントデータを返す

ウェブページの表示に Google Font Directory のフォントを利用したいときは、フォントごとに決まった URL を CSS ファイルとしてリクエストしておきます。それだけでもう、後に続くスタイル指定でそのフォントを使う準備が整うのですが、じつは、Google は、リクエスト元の環境に応じて異なる CSS を返してきています。実験結果は次のとおりです。

■外部 CSS ファイルとしてリクエストする URL

http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz

■返ってくる CSS : Safari 4 (Mac OS X) の場合

@font-face {
    font-family: 'Yanone Kaffeesatz';
    font-style: normal;
    font-weight: 400;
    src: local('Yanone Kaffeesatz'), url('ファイルパス') format('truetype');
}

■返ってくる CSS : Safari (iPhone OS 3) の場合

@font-face {
    font-family: 'Yanone Kaffeesatz';
    font-style: normal;
    font-weight: 400;
    src: local('Yanone Kaffeesatz'), url('ファイルパス#YanoneKaffeesatz') format('svg');
}

@font-face ルールでフォントを定義する CSS が記述されていますが、src の末尾を比較してみると、指定フォーマットが異なっています。

(上記、記事の横幅の関係で、CSS 中のファイルパスを省略しました。あしからずご了承ください)

なぜこんなことをしているかというと、ブラウザごとに @font-face の実装段階や対応フォーマットが異なっているためです。Google Font API は、ブラウザを判別した上で、そのブラウザが対応している形式のフォーマットを指定する CSS を返してきます。フォントファイルの所在を示す url の記述は実質同一ですが、おなじ URL であっても、アクセスするブラウザによって返ってくるデータが異なることを確認できました(たとえば Internet Explorer には EOT ファイルが返ってきます)。

ブラウザごとの対応フォーマットについては、「フォントブログ」さんが、下記記事の下の方で、わかりやすい一覧表にまとめてくださっています。

» ウェブで任意の書体を使う方法まとめ - フォントブログ

iPhone / iPad の Safari で日本語が消える理由

さて、上の実験から、Google Font API は iPhone の Safari に対して SVG フォントで対応する、ということがわかりました。これは、現在の iPhone 版 Safari で @font-face によるウェブフォント指定として有効になるのが SVG フォントのみだからです。Mac OS X の Safari では可能な TrueType フォントが利用できないのは、iPhone OS におけるファイル取り扱いの制約のひとつではないかと推測されます(あくまで推測です)。

一方、Safari や Google Chrome などで用いられている WebKit は、SVG フォントの扱いにまだ問題があります。一方、Safari や Google Chrome などで用いられている WebKit はそもそも、iPhone / iPad 版であるかどうかに拠らず、ある条件を持った SVG フォントで日本語文字(や、フォント内で未定義の文字)を表示させようとしても、その文字を本来の字形では表示しません。たとえば Google Font API の SVG フォントの場合は空白となります。そしてこれは、決してあやまった挙動とはいえないように思います。

ある文字列を SVG フォントで表示するよう CSS に指定があり、その文字列に含まれる文字の字形が SVG フォント内で定義されていないとき、本来期待される挙動は、font-family でより下位に指定されたフォントや、親要素に指定されたフォント、なにも指定がなければデフォルトのフォントで表示することなのですが、現時点の WebKit は、その文字を表示できないまま描画を終えてしまいます。WebKit がこのように振る舞う条件となるのは、SVG フォントのファイル中における missing-glyph 要素の記述です。

(ここから追記)missing-glyph 要素は、描画対象の文字の字形データがないときに使用される図像を定義するための属性です(Fonts - SVG 1.1)。

WebKit はどうやら、この要素が存在すると、仮にその要素内で具体的な図像形状がで示されていなくても、あくまで「missing-glyph の指定があった」として振る舞うようです。その結果、日本語その他、欧文フォントにおける missing-glyph に該当する文字列はすべて、未定義の図像、つまりなにも描画されない空白として表示されていると考えられます。

おそらく Google Font API の SVG フォント内にも、図像の形状を示さない missing-glyph 要素が存在しているものと思われます。ユーザエージェントを iPhone に偽装しただけでは SVG フォントデータを取得することができないために未検証なのですが、たとえば Font Squirell が提供している @font-face Generator で変換した SVG フォントにも、そうした形状を明示しない missing-glyph 要素が含まれていました。(ここまで追記)

もうおわかりですよね。今回の問題は、日本語の字形データを持たない SVG フォントを、WebKit ブラウザである Safari で、日本語に適用したために起きていると考えられます。つまり今回の問題は、日本語の字形データを持たず、missing-glyph 要素がある(さらにそこで代替の指定がなされてない)SVG フォントを、WebKit ブラウザである Safari で、日本語に適用したために起きているものと想像されます。

ちなみに、iPhone でなく Mac OS X の Safari や Google Chrome でも、フォント形式として敢えて SVG を指定すると、おなじ現象が発生します。これは、前述のとおり iPhone / iPad の Safari だから、というわけではなく、WebKit の仕様のようです。ただし、Google Font API が SVG フォントを返すのが iPhone / iPad 版のときだけなので、iPhone / iPad でだけ問題が発生したというわけですね。

補足(追加)

(ここから追記)なお、Opera も SVG フォントに対応していますが、Opera の場合、上記のような missing-glyph 要素があっても、未定義文字は代替フォントで表示します。ただし、Opera の場合、逆に missing-glyph に代替の図像形状を明示しても、未定義の文字はその形状で表示されません。一方の WebKit では、形状の指定があれば、正しく missing-glyph としての役割を果たすようです。Opera の挙動がおかしいのはどうやら明らかですが、個人的には、具体的な形状指定がない場合には missing-glyph を無視してくれればいいのに、と WebKit にも贅沢を言いたい気持ちが湧きます。

ただ、missing-glyph 要素を記述しなければ、WebKit でも日本語などの未定義文字をきちんと表示することができるようです。そういう意味では、Google Font API 側が、提供する SVG フォントの仕様を見直してくれれば解決することなのかもしれません。現状の WebKit の仕様はむしろ正しく、SVG フォントの仕様として missing-glyph は必須の要素ではないのではないか、と、そう思うのですが、どうなのでしょう、ちょっと正確な調べがつきませんでした。(ここまで追記)


まとめ

以上が、Google Font API 経由の欧文フォントを日本語文字列に対して指定すると iPhone / iPad で表示されなくなる理由だと考えられます。そして、これは日本語文字列に限らず、フォント内に字形定義のない文字すべてに当てはまります。みなさま、どうかご注意ください。

さて、最初に述べたとおり、CSS の仕様書のなかで、ブラウザは、指定フォントが字形データ(グリフ)を持たないときは代替フォントでの表示を試みるよう求められています。ただし、SVG フォントの使用や、そもそも @font-face による外部フォントの指定は、かつて一旦見送りになったのち、現在まだ策定中の CSS 3 で再び定義されることになった内容であり、各ブラウザがそれに対応しているのは、あくまで先行実装に過ぎません。

(追記)さらに、missing-glyph を条件とする WebKit の振る舞い変化は、CSS のフォント決定ルールを逸脱しているとはいえず、逆にこれこそ正しい挙動といえるのかもしれない、というのも前述のとおりです。

SVG フォントが絡まない状況では WebKit も期待通り振る舞うので、まだ将来の技術仕様である SVG フォントが絡んだときに期待しない振る舞いをしたとしても、WebKit や Safari を責めることはできません。ブラウザごとの挙動が異なっていたり、あるブラウザの挙動が制作者にとって期待どおりではなかったりしたとしても、まだ将来の技術仕様に関するものであれば、残念であっても文句はいえません。

ただ、ウェブの表現を大きく広げる可能性を持った、ウェブフォントや他の様々な技術への期待と共に、WebKit への期待も持ち続けたいですね。ただ、ウェブの表現を大きく広げる可能性を持ったウェブフォントや他の様々な技術への期待と共に、それに対応したサービスやブラウザの発展への期待も持ち続けて、ときには提供者にフィードバックしつつ、よいものは積極的に取り入れていきたいと思います。

お読みいただき、ありがとうございました!