Web フォントの表示の最適化 〜 Font Loading API 〜

1. Overview

Web フォントはその性質上, ブラウザがテキストの表示に必要なフォントを知ることができるのは他のリソースと比較するとずっと後になります.

  1. @font-face が含まれた CSS をロード
  2. スタイルとドキュメントを結合した視覚部分を表現するツリーの構築
  3. テキストとフォントの関係が示された時に, 必要なフォントを確定する

といった, フローとなっているからです. これが引き起こす問題として, FOUT (Flash of Unstyled Text) / FOIT (Flash of Invisible Text) があります.

FOUT

リクエストしたフォントがロードされるまでの間, いくつかのブラウザではタイムアウトするまでの時間が設定されています. タイムアウトまでの間にロードが完了しなかった場合は, 代替フォントが表示され, 代替フォントから指定フォントへの切り替わりの瞬間にチラつきが発生する問題です.

FOIT

ブラウザによってはフォントのロードを待ち続けるように実装されているものもあり, その場合はロードが完了するまでテキストが表示されなくなる問題です.

これらの問題を解決する具体的な手段として, Font Loading API という JavaScript の API が仕様策定されています.

2. Font Loading API

フォントのリソースをロードするためのメソッドが定義されており, あわせてフォントの状態を検知する手段もいくつか定義されています. これによって, @font-face では困難な細かな制御を可能にします.

具体的なコードを見てみましょう.


// 第 1 引数は, `font-family` となる文字列
// 第 2 引数は, フォントファイルの URL か `ArrayBuffer`
// 第 3 引数は, オプションで `{ unicodeRange : 'U+0100-024F' }` などを指定します
const font = new FontFace('Source Code Pro', 'url(source-code-pro.woff2)');

// `FontFace` のインスタンスは, `Promise`
font.load()
  .then(loadedFace => {
    document.fonts.add(loadedFace);
    document.body.style.fontFamily = `'Source Code Pro', monospace`;
  });

`FontFace#load` は, 評価された時点でフォントのリソースを要求するので, リクエストの遅延を少し早めることができます.

以下のコードは, タイムアウトによるフォールバックが必要な場合の実装例です.

const font = new FontFace('Source Code Pro', 'url(source-code-pro.woff2)');
const timeout = 3000;

Promise.race([new Promise((resolve, reject) => setTimeout(reject, timeout)), font.load()])
  .then(loadedFace => {
    // 指定したフォントのロードが完了した場合
  })
  .catch(() => {
    // 指定したフォントのロードに失敗した場合
  });

3. Reference

コメントを残す