使いやすくて便利なWebフォントの代表格「GoogleFont」ですが、フォントはどうしたって結構なデータサイズなので、PageSpeedInsightsなどで表示速度をテストしてみると、「レンダリング(ブラウザがページを表示させるためにデータを読み込むこと)を妨げている要因」として怒られます。
ですので、サイトでGoogleFontを利用するときはレンダリングをストップさせないように対策するものですが、先日手持ちのPCとスマホで動作を確認していると、どうしても上手くいかない事態に直面しました。
おかしいな〜設定は間違ってないはずなんだけどなぁ、、と試行錯誤した結果、
「10年以上前の古い端末で動作確認するやつが悪い」
という結論に落ち着いたのですが、せっかく調べ直したので記事にまとめておこうと思います。
rel=preload で読み込みの優先度を調整する
ブラウザがサイトを表示させる際、最初にheadタグの記述を全て読み込み、headの読み込みが完了したらbodyタグを読み込む という順番にレンダリングしていきます。
このとき、headタグに書かれた type=text/css(cssファイル)と、 type=text/javascript(java scriptファイル)はレンダリングをストップさせる要因となります。この2つのファイルがあった場合、それらのsrcファイルを読み終わるまでサイトのレンダリングは停止した状態となります。
そこで、rel=preloadという属性を利用します。
preloadとはそのまま「先に読み込み」です。レンダリング開始よりも先にpreload指定したファイルの読み込みを開始させることで、他のレンダリングを妨げないように仕向けます。結果として、サイトの表示速度につながる可能性がある という仕組み。
GoogleFontの設定例
例で、NotoSerifを利用すると仮定します。
GoogleFontのページからNotoSerifを指定、利用したいfont weightを選択すると、次のようなコードが表示されるはずです。
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Noto+Serif+JP:wght@900&display=swap" rel="stylesheet">
preloadを設定する
一行目の「preconnect」(事前接続)は、サーバー間のネットワーク接続を、必要になる前に可能にしておく設定です。執筆時時点でIE以外の主要ブラウザに対応しています。これは重要なのでこのままで。
で、二行目のスタイルシート読み込みをpreloadで先読みの対象にしてやります。(rel=prefetchでも同様の効果が期待されますが、prefetchは優先度が低く実行が保証されません(多分)。そういうわけで強制力の強いpreloadを使用します。)
<link rel="preload" href="https://fonts.googleapis.com/css2?family=Noto+Serif+JP:wght@900&display=swap" as="style">
relにpreloadを指定。 as= でファイルの種類を指定します。asでは他に画像や動画、フォント、scriptなど12種類の指定が可能です。
たとえばファーストビューで使用される画像ファイルを
<link rel="preload" href="mainImage.jpg" as="image">
とpreloadしておき、表示速度を向上させる方法もあります。asで指定できるファイルは以下12種類です。
asの値 | ざっくりした説明 |
---|---|
style | CSS |
script | java script |
font | fontファイル。必ず crossorigin を付ける |
image | 画像 imagesrcset属性を使ってレスポンシブ設定も可能 |
movie | 動画 |
audio | オーディオ |
document | iframe |
embed | embedタグに対応 |
object | objectタグに対応。pdfとか |
track | trackタグに対応。(track : 動画の字幕やキャプションなど。vttファイル) |
fetch | fetch。JSONなど |
worker | バックグラウンドで働いているオブジェクト |
参考:MDN
preload は読み込みだけで実行はしない
preload属性を指定されたファイルは読み取り専用なので、それしか書いていないと実行されません(cssでいえば、スタイルがサイトに適応されない)
ですので、preloadとは別に通常のrel=stylesheetも用意しないといけないのですが、それでは結局スタイルシート読み込みでレンダリングストップしてしまいます。
polyfilも用意されているのですが、現在の最善策は以下のコード。
<!-- 一行目略 -->
<link rel="preload" href="https://fonts.googleapis.com/css2?family=Noto+Serif+JP:wght@900&display=swap" as="style">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Noto+Serif+JP:wght@900&display=swap" media="print" onload="this.media='all'">
追加した3行目の解説ですが、まずmedia=print (印刷ページ用のCSS) を指定します。印刷用cssは印刷ページ以外では読み込まれないので、レンダリングをストップさせることがありません。
そこに、onload= this.media = all を指定(ロード完了したらmediaタイプをallに変更)することで、スタイルをサイトに適応させます。
あらかじめpreloadで指定したスタイルを読み込んでいるので、ロード完了後すぐにスタイルが反映されるという仕組み。