Webfontの使い方

Webフォントを使うためのベストプラクティス（最もパフォーマンスがよい、遅延が少ない）をGoogle Fontsの利用を中心に考えてみたいと思います。
## 形式
EOT・TTF・WOFF・WOFF2・SVG等ありますが、2019年12月現在、ほとんどのブラウザでWOFFとWOFF2がサポートされていますので、この2つを読み込めばOKです。
※但し、案件ごとのターゲットブラウザは確認しましょう。
![スクリーンショット 2019-09-30 12.57.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298406/20f08d59-f65e-ba65-dad2-2b5d01f9548e.png)
![スクリーンショット 2019-09-30 12.57.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298406/d7a68540-fea6-045d-5816-3fd2d317903c.png)
## Google FontsのCDN利用
Google Fontsを<link>タグで読み込んで使う場合、複数フォントを読み込むと以下のようなタグが発行されます。

```
<link href="https://fonts.googleapis.com/css?family=Noto+Sans+JP:400,700|Roboto:400,700&display=swap&subset=japanese" rel="stylesheet">
```
W3Cのチェッカーでエラーでますので、文法エラー回避のためには、`｜`でなく`%7C`を使います。
<dl>
<dt>メリット</dt>
<dd>楽に使える</dd>
<dt>デメリット</dt>
<dd>レンダリングブロックが発生する</dd>
<dd>ファイルパスが変わる可能性がある</dd>
</dl>
## ブラウザによる挙動の違い
![スクリーンショット 2019-09-30 14.44.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298406/11f47aa1-0d29-86f7-5ac7-df950584caa2.png)

## 発生しやすい問題
### FOUT（Flash of Unstyled Text）
Webフォントの読み込みが完了するまで代替フォントで表示され、読み込みが完了するとWebフォントに切り替わる現象。
Chromeなどのブラウザはタイムアウトまでにロードが完了しなかった場合、代替フォントが表示され、フォントダウンロード後に指定フォントに切り替わるため、そのときにチラつきが発生する問題。
### FOIT（Flash of Invisible Text）
Webフォントの読み込みが完了するまで、テキストが表示されない現象。
Safariではフォントのロードを待ち続けるように実装されているため、フォントのダウンロードが完了するまでテキストが表示されなくなる問題。
## CSSによる最適化
前項のように、ブラウザによって挙動の違いがあり、FOUTやFOITのような問題が発生する場合があります。
`font-display`プロパティは、フォント読込中の挙動をCSSから制御することができます。
<dl>
<dt>メリット</dt>
<dd>レンダリンクブロックが発生しない（非同期読み込み）</dd>
<dd>細かくフォントの挙動を制御できる</dd>
<dd>Edge、IEでの利用可能</dd>
</dl>
![スクリーンショット 2019-09-30 15.19.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298406/c8712d6e-a0b7-6efd-302b-114009651824.png)

+ `auto`は、ブラウザのデフォルトの挙動です。
+ `block`は、タイムアウトがなくなるため、FOUTはなくなるが、FOITが発生しやすくなります。
+ `swap`は、ブロック期：0秒、スワップ期：無限で、FOITはなくなるが、FOUTが発生しやすくなります。
+ `fallback`は、ブロック期：0.1秒、スワップ期：3秒で、フォールバックフォント表示が許容される場合に使用します。
+ `optical`は、ブロック期：0.1秒、スワップ期：０秒で、FOUTは発生せず、FOITも最小限です。ただし、フォントを取得するかどうかブラウザ任せになるため、早いテキスト表示を優先する場合に使うとよいです。

## JavaScriptによる最適化
### Font Loading API
フォントのダウンロード進行状況の監視や挙動の制御ができるが、ブラウザの実装に差があるため、次に紹介するWeb Font Loaderのほうが使いやすいです。
### Web Font Loader
GoogleとTypekitが共同開発したフォントの読み込みを制御できるJavaScriptライブラリ。ソースコードは[GitHub](https://github.com/typekit/webfontloader)で公開されており、無料で利用できます。使い方は<b>Noto Sans JPの使用例</b>にて後述します。
## preloadによる最適化
![スクリーンショット 2019-09-30 16.00.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298406/13c37b14-6884-08e7-cc9d-3403881b458d.png)
<dl>
<dt>メリット</dt>
<dd>Web Font Loaderより読み込み（レンダリング）が早い</dd>
<dd>AMPでも利用可能</dd>
<dt>デメリット</dt>
<dd>IE、Firefox非対応</dd>
<dd>CDNは使えない</dd>
<dd>FOUTが発生する可能性はある</dd>
</dl>
## Noto Sans JPの使用例
```ruby:HTML
<script>
  WebFontConfig={
    google:{
      families:['Roboto:400,700', 'Noto+Sans+JP:400,700']
    },
    active: function() {
      sessionStorage.fonts = true;
    }
  };

  if (typeof WebFont === 'object') {
    WebFont.load(WebFontConfig);
  }
</script>

<script src="https://ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js" async></script>

<link rel="preload" as="font" href="/assets/fonts/yakuhanjp/YakuHanJP-Regular.woff2" crossorigin>
<link rel="preload" as="font" href="/assets/fonts/yakuhanjp/YakuHanJP-Bold.woff2" crossorigin>
<link rel="preload" as="font" href="/assets/fonts/yakuhanjp/YakuHanJP-Regular.woff" crossorigin>
<link rel="preload" as="font" href="/assets/fonts/yakuhanjp/YakuHanJP-Bold.woff" crossorigin>
```
```rudy:CSS
@font-face {
  font-family: "YakuHanJP_Noto";
  font-weight: 400;
  font-style: normal;
  src: url("/assets/fonts/yakuhanjp/YakuHanJP-Regular.woff2") format("woff2"), url("/assets/fonts/yakuhanjp/YakuHanJP-Regular.woff") format("woff");
  font-display: swap;
}

@font-face {
  font-family: "YakuHanJP_Noto";
  font-weight: 700;
  font-style: normal;
  src: url("/assets/fonts/yakuhanjp/YakuHanJP-Bold.woff2") format("woff2"), url("/assets/fonts/yakuhanjp/YakuHanJP-Bold.woff") format("woff");
  font-display: swap;
}
}
```
### sessionStorageの使用
ブラウザを閉じるまで、ページ遷移してもWebフォントを再読み込みする無駄が発生しないようにしています。
### 非同期の読み込みファイルはscriptタグで記述
GithubのREADMEの記述は、スクリプトインジェクション等の可能性があり、脆弱性の観点からあまりよい記述でないといえます。シンプルにscriptタグのasync属性を利用したコードで記述しています。 
また、非同期で読み込んだ場合、WebFont.load()が実行されるタイミングでWeb Font Loaderの読込が完了していない可能性があるため、WebFontのtypeofをチェックして未完了の時は実行されないようにしています。
### Noto Sans JPで気になる約物はYaku Hans JPを使用
半角の約物だけのWebフォントで、Noto Sansに最適化されたフォントファイルもあります。
[https://github.com/qrac/yakuhanjp](https://github.com/qrac/yakuhanjp)
_例としてYaku Hansにはpreloadを使っていますが、WebFontLoaderでも記述できます_
## 参照元
[ウェブフォントの最適化  |  Web Fundamentals  |  Google Developers](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/webfont-optimization#_7)
_「ブラウザによる挙動の違い」の掲載内容は、参照元から転用させていただいています。_