Close

Web技術Tips

Homepage Tips Homepage Tips

ホーム Web技術Tips Google Fonts APIのソースコードを調べてみました

SHARE

フォントAPI 2022.06.15(公開)

Google Fonts APIのソースコードを調べてみました

早期アクセスの頃と比べたらフォントの読み込みスピードは改善されたとは言え、まだまだページ表示速度のボトルネックとなることが多い Google フォントですが、このスタイルシートの中身を調べてどのようにフォントの読み込みがされているのかを知って、可能であればページ表示速度改善のヒントにしたいです。

Google フォントを使う方法はいくつかありますが、最もメジャーなのは<head>内に以下のコードを追加する方法です。

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@700&display=swap" rel="stylesheet">

これは Noto Sans の日本語フォントを指定するコードです。
読み込みたいフォント名とウェイトを指定し、API から受け取ったファイルをスタイルシートとして読み込んでいます。
このコードを<head>内に置くだけでそのページで Noto Sans JP を自由に使うことが出来ます。

preconnectは外部リンクのネットワーク接続を事前に行う指定です。
fonts.googleapis.com は直後に読み込む API のドメインです。
fonts.gstatic.com のほうは@font-faceで Web フォントを読み込むときに使われています。

Google Fonts API から受け取ったスタイルシートを見てみる

fonts.googleapis.com から受け取ったスタイルシートの中身を見てみます。

/* [0] */
@font-face {
font-family: 'Noto Sans JP';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(https://fonts.gstatic.com/s/notosansjp/v42/-F6pfjtqLzI2JPCgQBnw7HFQei0q1xVxjfp_dakBof6Bs-tb3ab2FNISVac.0.woff2) format('woff2');
unicode-range: U+25ee8, U+25f23, U+25f5c, U+25fd4, U+25fe0, U+25ffb, U+2600c, U+26017, U+26060, U+260ed, U+26222, U+2626a, U+26270, U+26286, U+2634c, U+26402, U+2667e, U+266b0, U+2671d, U+268dd, U+268ea, U+26951, U+2696f, U+26999, U+269dd, U+26a1e, U+26a58, U+26a8c, U+26ab7, U+26aff, U+26c29, U+26c73, U+26c9e, U+26cdd, U+26e40, U+26e65, U+26f94, U+26ff6-26ff8, U+270f4, U+2710d, U+27139, U+273da-273db, U+273fe, U+27410, U+27449, U+27614-27615, U+27631, U+27684, U+27693, U+2770e, U+27723, U+27752, U+278b2, U+27985, U+279b4, U+27a84, U+27bb3, U+27bbe, U+27bc7, U+27c3c, U+27cb8, U+27d73, U+27da0, U+27e10, U+27eaf, U+27fb7, U+2808a, U+280bb, U+28277, U+28282, U+282f3, U+283cd, U+2840c, U+28455, U+284dc, U+2856b, U+285c8-285c9, U+286d7, U+286fa, U+28946, U+28949, U+2896b, U+28987-28988, U+289ba-289bb, U+28a1e, U+28a29, U+28a43, U+28a71, U+28a99, U+28acd, U+28add, U+28ae4, U+28bc1, U+28bef, U+28cdd, U+28d10, U+28d71, U+28dfb, U+28e0f, U+28e17, U+28e1f, U+28e36, U+28e89, U+28eeb, U+28ef6, U+28f32, U+28ff8, U+292a0, U+292b1, U+29490, U+295cf, U+2967f, U+296f0, U+29719, U+29750, U+29810, U+298c6, U+29a72, U+29d4b, U+29ddb, U+29e15, U+29e3d, U+29e49, U+29e8a, U+29ec4, U+29edb, U+29ee9, U+29fce, U+29fd7, U+2a01a, U+2a02f, U+2a082, U+2a0f9, U+2a190, U+2a2b2, U+2a38c, U+2a437, U+2a5f1, U+2a602, U+2a61a, U+2a6b2, U+2a9e6, U+2b746, U+2b751, U+2b753, U+2b75a, U+2b75c, U+2b765, U+2b776-2b777, U+2b77c, U+2b782, U+2b789, U+2b78b, U+2b78e, U+2b794, U+2b7ac, U+2b7af, U+2b7bd, U+2b7c9, U+2b7cf, U+2b7d2, U+2b7d8, U+2b7f0, U+2b80d, U+2b817, U+2b81a, U+2d544, U+2e278, U+2e569, U+2e6ea, U+2f804, U+2f80f, U+2f815, U+2f818, U+2f81a, U+2f822, U+2f828, U+2f82c, U+2f833, U+2f83f, U+2f846, U+2f852, U+2f862, U+2f86d, U+2f873, U+2f877, U+2f884, U+2f899-2f89a, U+2f8a6, U+2f8ac, U+2f8b2, U+2f8b6, U+2f8d3, U+2f8db-2f8dc, U+2f8e1, U+2f8e5, U+2f8ea, U+2f8ed, U+2f8fc, U+2f903, U+2f90b, U+2f90f, U+2f91a, U+2f920-2f921, U+2f945, U+2f947, U+2f96c, U+2f995, U+2f9d0, U+2f9de-2f9df, U+2f9f4;
}
/*
 
~中略~
 
*/
/* [119] */
@font-face {
font-family: 'Noto Sans JP';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(https://fonts.gstatic.com/s/notosansjp/v42/-F6pfjtqLzI2JPCgQBnw7HFQei0q1xVxjfp_dakBof6Bs-tb3ab2FNISVac.119.woff2) format('woff2');
unicode-range: U+20, U+2027, U+3001-3002, U+3041-307f, U+3081-308f, U+3091-3093, U+3099-309a, U+309d-309e, U+30a1-30e1, U+30e3-30ed, U+30ef-30f0, U+30f2-30f4, U+30fb-30fe, U+ff0c, U+ff0e;
}

一般的な Web フォントと同じように @font-face を使ってフォントをロードしています。
こんな感じの@font-face が延々と続くのですが、フォントデータは一度に読み込むのではなく分割して読み込んでいるようです。
Noto Sans JP は 6,992 文字もある大容量のフォントなので、データを 120 分割してバラバラに読み込んでいるんですね。
英語フォントは数ファイルの場合もあるので、いかに日本語ファイルが巨大で重たいかが分かります。

また、フォントのフォーマットはwoff2です。
IE11 はwoff2に対応していないブラウザなのでwoff形式で読み込まれるのですが、IE11 はまもなくサポート終了するため、モダンブラウザではwoff2が読み込まれます。

display=swapでfont-displayプロパティが追加される

Google Fonts からコピーした<link>タグにはdisplay=swapというパラメータが指定されています。
この指定によって@font-facefont-display: swap;というスタイルが追加されます。
Web フォントはデータなのでダウンロードの時間があるのですが、font-display: swap;の指定でフォントダウンロード中は標準フォントを代わりに表示させます。

FOUT と FOIT の違い

フォントがダウンロードさせるまで代わりのフォントを表示させておくことを FOUT(Flash of Unstyled Text)と呼びます。
もうひとつの方法としてフォントがダウンロードさせるまで何も表示しないことを FOIT(Flash of Invisible Text)と呼びます。

FOUT のメリットとしてはフォントのレンダリングが止まっている時間がないので、フォントのダウンロードに時間がかかったり失敗したりしてもひとまず何らかのフォントが表示されていることです。
一方でデメリットは Web フォントを適用するときにフォントの差や文字サイズの違いによりレイアウトの高さが変わったりすることです。
FOIT・FOUT に関してはどちらが良いというのは個人の好みに委ねられる部分が大きいので、どちらにするべきかはメリット・デメリットで判断するべきです。

unicode-rangeでは何が指定されている?

見慣れないunicode-rangeというプロパティはなんでしょうか。
unicode-range - CSS: カスケーディングスタイルシート | MDN

unicode-rangeとは、@font-faceでフォントをロードするときに使うプロパティです。
unicode-rangeで文字範囲を指定するのですが、ページ上で1文字でも範囲の文字が使われているとそのフォントが読み込まれます。
つまり、その範囲の文字を1文字も使っていなければそのフォントデータは読み込まれないわけです。

unicode-rangeで指定しているU+25ee8という文字は、「𥻨」という漢字の Unicode 上での位置を表すコードポイントと呼ばれる番号です。
U+ という符号は必ず付き、その後に16進数でコードポイントを続けます。
「𥻨」という見たことない漢字は姫と同じ読みをするみたいです。
Noto Sans はこのようなマイナーな漢字も含んでいるのでデータが膨大なのですが、実際に読み込んでいるデータは可能な限り少なくなっています。

あと、U+26ff6-26ff8のような連結した文字はU+26ff6, U+26ff7, U+26ff8の短縮形ですね。

ブラウザはそのページで使われている文字のフォントのみを読み込んでいる

DOE のトップページではこんなフォントデータが読み込まれていました

デベロッパーツールの [ネットワーク] で調べてみると、実際にはすべてのフォントデータを読み込んでいるわけではなく、ページ上で表示しているフォントに合わせてフォントデータを読み込んでいます。
非同期で別のページを開いたときに、まだ Web フォントを読み込んでない文字があるなら追加でフォントデータが読み込まれます。

ページ移動すると追加でフォントが読み込まれる

Webフォントのロードを高速化する方法として、動的にフォントをサブセット化するダイナミック・サブセッティングという方法があるのですが、unicode-rangeを使った選択的なフォントの読み込みはサブセット化はしていないので当てはまらないです。
ただ結果的に読み込むファイルを限定的にしてフォントのロードを高速化しています。

極端な話、使用する文字を少なくすれば読み込まれるフォントデータの数も少なくなり、パフォーマンスが上がるかもしれません。

実験:分割した120ファイルの文字を1文字づつ表示するページでは、すべてのフォントデータを読み込むことになるのか?

Web フォントの読み込みでunicode-rangeを指定しない場合は、初期値であるU+0-10FFFFが指定されます。
しかしその場合でもすべてのファイルが読み込まれるのではなく、通し番号でいうと 82~119 のフォントのみ読み込まれていた。
そこで各 unicode-range に指定されている文字を1文字づつ表示したらすべての Web フォントデータを読み込むことになるのか試してみました。

<p style="font-family:'Noto Sans JP';">𥻨 U+25ee8 🈵 U+1f235 ᅲ U+ffd7 塚 U+fa10 來 U+f92d 麋 U+9e8b 鰾 U+9c3e 髥 U+9ae5 飫 U+98eb 霝 U+971d 鑊 U+944a 銼 U+92bc 酃 U+9143 轒 U+8f52 跀 U+8dc0 謭 U+8b2d 襳 U+8973 蟢 U+87e2 處 U+8655 蒴 U+84b4 苨 U+82e8 腊 U+814a 罷 U+7f77 絗 U+7d57 篈 U+7bc8 稗 U+7a17 硑 U+7851 皌 U+768c 甑 U+7511 獬 U+736c 煦 U+7166 潘 U+6f58 浼 U+6d7c 殅 U+6b85 槝 U+69dd 桕 U+6855 晾 U+667e 擒 U+64d2 拏 U+62cf 愗 U+6117 彬 U+5f6c 嶛 U+5d9b 宼 U+5bbc 妋 U+598b 垳 U+57b3 嘖 U+5616 吿 U+543f 劍 U+528d 僝 U+50dd 佗 U+4f57 䂓 U+4093 ㎕ U+3395 ㊵ U+32b5 ㇈ U+31c8 〨 U+3028 ⼔ U+2f14 ◤ U+25e4 ⓑ U+24d1 ℅ U+2105 ¡ U+a1 ∧ U+2227 ¨ U+a8 -9 U+2d9 ,a U+2ca ⑧ U+2467 ± U+b1 † U+2020 ⑦ U+2466 ├ U+251c ォ U+ff6b ♫ U+266b ¯ U+af 云 U+4e91 ∞ U+221e ミ U+ff90 ⑤ U+2464 ≦ U+2266 ∇ U+2207 串 U+4e32 △ U+25b3 ④ U+2463 ‐ U+2010 ℃ U+2103 ─ U+2500 〔 U+3014 ◇ U+25c7 $ U+24 ° U+b0 ▽ U+25bd ¥ U+a5 丘 U+4e18 ` U+60 ① U+2460 ⇒ U+21d2 ― U+2015 ↓ U+2193 七 U+4e03 ~ U+7e ○ U+25cb ↑ U+2191 丈 U+4e08 ▼ U+25bc = U+3d 倍 U+500d 丁 U+4e01 % U+25 ヶ U+30f6 # U+23 ★ U+2605 ♪ U+266a @ U+40 + U+2b 世 U+4e16 & U+26 > U+3e | U+7c © U+a9 N U+4e ! U+21 ‧ U+20</p>

1画面に収めようとしたため文字が読めないくらい小さくなってしまったのですが、120 ファイルが読み込まれているのを確認しました。

その他メモ

CSS APIはv1とv2でなにか違う?

<link href="https://fonts.googleapis.com/css?family=Noto+Sans+JP:700&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@700&display=swap" rel="stylesheet">

2021年に Google Fonts API はバージョンアップしていて、URL をよく見ると css が css2 になっています。
このバージョンアップでは可変フォントに対応しただけなので機能的な変化はありません

APIから受け取るスタイルシートは圧縮できない

fonts.googleapis.com から返されるスタイルシートはコメントアウトが入ってたりタブや改行が入っていて圧縮したくなりますが、基本的にこれらは圧縮して minify データにすることはできません。
もしやるならスタイルシートをダウンロードして手動で圧縮してローカルに設置という手段はありますが、あまりおすすめの方法ではありません。

textパラメータは速くなるか?

<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@700&display=swap&text=あいうえお" rel="stylesheet">

@font-face {
font-family: 'Noto Sans JP';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(https://fonts.gstatic.com/l/font?kit=-F6pfjtqLzI2JPCgQBnw7HFQei0q12VqZGuX91jkLBp0NTW3W0Ed&skey=b1468649b9c42538&v=v42) format('woff2');
}

事前に必要な文字が限られている場合は text パラメータで読み込む文字数を制限できます
たとえばひらがなのみであれば、API から返されるスタイルシートはかなり短くなるので軽量化に成功しています。

もちろん指定する文字数が多すぎるなら普通の API を使ったほうがよく、一説では 280 文字程度が限度らしいです。(参考:webフォントの軽量化に関してのメモ – WEBUTUBUTU

DOE(横浜)のニュースとブログ

News News

横浜のWeb制作会社DOEはホームページ制作に関連するWeb技術、Webデザイン、SEO対策情報など人気&おすすめ記事を随時公開中です。
尚、Twitterでは現場の声がリアルタイム配信中です。良かったらShareして繋がってください。