EagleLand

Webフォントのロードをやめた

Published at 2016-08-22

このサイトではフォントに Roboto と Roboto Mono を適用している。以前までは Google Fonts で配信されているそれぞれのフォントをロードしていたが、それをやめて font-family の指定のみに変更した。

プログレッシブな適用とOS共通フォントの選択

まず前提として、テキストのベースフォントとして明朝(serif)を、 <h1> ~ <h6> の見出しにはゴシック(sans-serif)を、コードには等幅(monospace)を適用する前提方針がある。明朝・ゴシック・等幅の中から自分の好みに近く、尚且つ Mac と Windows にインストールされているものを優先的に選ぶようにした。

body {
  font-family: YuMincho, serif;
  font-weight: normal;
}

h1, h2, h3, h4, h5, h6 {
  font-family: Roboto, Helvetica, Arial, sans-serif;
  font-weight: bold;
}

code {
  font-family: "Roboto Mono", "Source Code Pro", Consolas, "Courier New", monospace;
  font-weight: normal;
}

最も広域になるであろう <body> には Mac にも Windows にもインストールされている可能性が高い游明朝体(YuMincho)を指定した。游明朝体は Mac であれば OS X Mavericks (10.9)から、 Windows であれば Windows 8.1 から標準搭載されているので、大半の環境でこちらが適用される。

個人的に好きな Roboto と Roboto Mono の指定も残しておいて、閲覧者の環境にインストールされている場合は優先するようにしている。 Roboto と Helvetica はそこそこ近い見た目なので Mac ユーザーであれば Roboto をインストールしてなくともソツのない見た目になるはず。あとはシェアの大きい Arial でフォールバックさせている。

等幅フォントにも多少のこだわりがあって、 Roboto MonoSource Code ProConsolas が並んでいるのはそのせい。 Source Code Pro は Adobe 製で視認性の高い等幅フォントとして一時期流行ったので、インストールしている人も多そう。 Consolas は Windows 発の等幅フォントで Mac でも Office 製品のインストールと共にもれなくインストールされる、個人的にはイチオシの等幅フォント。どれもない人には Courier New が適用されるようにしている。

Flash of Unstyled Text

Web フォントのロードを避けた最大の理由は FOUT (Flash of Unstyled Text) である。

FOUT は、テキストに指定されている font-family のフォントが Web フォントとして指定されている場合に、ブラウザが フォントのロードが完了するまでテキストの描画を行わない 、もしくは 代替フォントで描画しておきロードが完了した時点で切り替える ことによってテキストがちらつく現象のこと。厳密に言えば前者の振る舞いは表示が遅延しているだけだが、フォントのロード待ちによって発生するテキストの描画遅延に変わりはないので今回はまとめて言及する。

FOUTにまつわる各ブラウザの挙動

現時点で次のような実装になっている。っぽい。

このように実装がブラウザによってまちまちなのも Web 開発者にとって悩ましいところ。これを見る限りは Internet Explorer の「ダウンロード完了まで代替フォントで表示する」のがパフォーマンス(ATF)の観点から言えば一番良さそうに見える。特にブログのようにテキストが主なサイトであれば、いち早く文字を表示しておきたいところだし、フォントのダウンロードに失敗したときに真っ白で終わるリスクが少ない。

問題は、ダウンロードが完了しフォントを切り替えるタイミングでレイアウトが発生する点である。フォント間でサイズギャップが大きいと読んでいる最中にガタつきが発生して、ユーザーにとってのストレスは大きい。 Chrome と Firefox はこれを避けるために3秒間の保留を選んでいるのだろう。

Font Loading API

この3秒間の保留をできる限り短くしたいとすれば、読み込むフォントのそのものを軽量化するのはもちろんのこと、フォントのリクエストからダウンロードまで早めることが重要である。 Web フォントは通常 CSS で定義するので、 CSS のダウンロードと評価に依存するが、これを打破するために JavaScript で命令的にフォントのロードをコントロールする Font Loading API というものがある。必要になるのがわかっているフォントはなるべく早いタイミングで Font Loading API を駆使してロード開始を早めておくと良い。

let font = new FontFace('Font Name', 'url(/font-name.woff2)', {
  style        : 'normal',
  unicodeRange : 'U+000-5FF',
  weight       : '400'
});

font.load();
font.ready().then(() => {
  document.fonts.add(font);
});

Font Loading API には bramstein/fontloader というポリフィルがあるので、ブラウザの実装が進むまではそちらを使うのも手。

font-displayプロパティ

また、フォントの表示に関してはブラウザの実装に依存しないように CSS でコントロールできるべきだとということで、 font-display というプロパティもある。 font-display はフォントの定義をする @font-face と共に使う。

@font-face {
  font-family: "Font Name";
  font-weight: 400;
  font-style: normal;
  src: url("font-name.woff2") format("woff2");
  font-display: swap;
}

font-display の値は次の通り。

swap は Internet Explorer の振る舞いで、 Chrome や Firefox に近いのは fallback ないし optional あたりだろうか。さらなる詳細については、 CSS-Tricks の font-display for the Masses という記事が詳しいのでそちらを参考に。

Webフォントを使わない選択

Font Loading API や font-display を駆使すると共に、 Cache API などを使ってフォントファイルを完全にキャッシュさせればバンドルフォントの参照に近い振る舞いを期待できそうではあるが、このブログでは冒頭の プログレッシブな適用とOS共通フォントの選択 で充分だったし、管理コストも考えて Web フォントを使わない選択をとった。自分は必要性に駆られなかったが、 Web フォントを使いたい場合は Noto Sans の Web Font 対応とサブセットによる最適化 の内容を理解した上で利用すべきだろう。

タイトルと URL をコピーしました