Webフォント「Google Fonts」非同期で読み込んでページ表示を速くする方法

よこのじ(@yokonoji_work)です。

標準フォント游ゴシック(Yu Gothic)をWebサイトで使うことを検討しました」にて、Google Fontsを使うべきだとご紹介しましたが、デメリットとして読み込みに時間がかかる点を挙げました。今回は、ページの表示速度にも配慮した設計として、WebフォントであるGoogle Fontsを非同期で読み込む方法をご紹介します。

Google Fontsを非同期で読み込む方法

<link rel=”preload”>を使って、Google Fonts「Noto Sans JP」の非同期読み込みを行います。

linkタグのrel属性には、dns-prefetch, preconnect, prefetch, prerenderのような、リンク先のリソースを事前に読み込む方法が用意されています。一方、preloadはこれらとは異なり、preloadの記述がある現在のページでレンダリングブロックを発生させずに非同期で読み込む方法になります。scriptの読み込みにおけるasyncやdeferのような感じで使用します。

次のようにrel属性にpreloadを指定するだけで、簡単に利用できます。

<link rel="preload" as="style" href="https://fonts.googleapis.com/css?family=Noto+Sans+JP" crossorigin="anonymous">

as属性で読み込むリソースの種類を指定しています。また、crossorigin属性は空の場合anonymousになるのですが、明示のために記述しています(記述なしでもOKです)。

crossorigin属性は、CORS(Cross-Origin Resource Sharing)というオリジン間でのデータ共有に関する約束事に関する指定です。異なるオリジン間でデータをやり取りするにはセキュリティ上注意が必要になることもありますので、HTTP認証などの認証を求めるかどうかをanonymous/use-credentialsで指定します。

anonymous:認証情報は不要
use-credentials:認証情報を求める

オリジンとは、スキーム、ホスト、ポートを組み合わせたもののことです。

スキーム:http:// or https://
ホスト:example.com
ポート:80

さて、preloadについて注意する点としては、preloadはあくまでも非同期で読み込むための指示であることです。通常はrel属性にrel=”stylesheet”と記述することで読み込んだcssを適用しています。しかし、preloadはダウンロードするだけですので、何らかの方法で読み込んだスタイルシートを適用させる必要があります。

参考:How to preload Google Fonts using resource hints

そこで、次のような記述を行います。

<link rel="preload" as="style" href="https://fonts.googleapis.com/css?family=Noto+Sans+JP" onload="this.rel='stylesheet'">

イベントハンドラonloadを検出して、rel=”preload”をrel=’stylesheet’に書き換えています。これにより、ページ内のリソースの読み込みが完了した時に、非同期で事前に読み込んでいたNoto Sans JPのcssを適用させることができます。

この方法では、onloadを検出するまでの時間が長いとNoto Sans JPの適用が遅れ、標準フォントで一時的に表示される場合があります。また、Chrome, Firefox, Operaではフォントのダウンロード待ちが3秒続いてはじめて標準フォントが表示されますので、それまでは文字がない状態となります。

参考:Controlling Font Performance with font-display

このような感じですね。

17-web-font-google-onload

そのため、onloadまでの時間を3秒未満にして、空白の時間を短くしつつ、標準フォントが表示されないようにしたいところです。

思いつくのは、DOMContentLoadedを利用してloadイベントより前にrel=’stylesheet’への書き換えを実行することです。

<link id="link-preload" rel="preload" as="style" href="https://fonts.googleapis.com/css?family=Noto+Sans+JP">

<script>
  document.addEventListener('DOMContentLoaded', function(){
    var link = document.getElementById('link-preload')
    link.rel = "stylesheet";
  }, false);
</script>

DOMContentLoaded画像などのリソースの読み込み完了を待たず、htmlの読み込み完了により検出できるので、loadより早いタイミングとなります。この方法でも3秒以内にGoogle Fontsの適用が完了するかは、各ページの状況次第ですがloadを待つよりは良いかと思います。

参考:rel=”preload” によるコンテンツの先読み
参考:resouce hintsとpreloadを使ってリソースの取得を最適化する

 

最後にpreloadの困ったところですが、主要ブラウザFirefox 64や開発が終了しても未だにシェアはあるIE 11では対応していません。

Can I use preload ?

この点については游ゴシックなどの標準フォントで対応するのか、他の処理を入れるのか検討の余地があります。どのブラウザのどのバージョンまで対応させるのかというのはまた難しい問題ですね。