イマドキの日本語Webフォント導入のお話

この記事は [株式会社エス・エム・エス Advent Calendar 2023](https://qiita.com/advent-calendar/2023/bm-sms)の25日目の記事です。

普段は、株式会社エス・エム・エスのヘルスケア事業部に所属し開発を担当している今村と申します。

私は自分のエンジニアとしてのスキルを磨き続ける手段として、いわゆる「個人開発」に挑戦しています。その一環で、今年は「文章を投稿すること」を目的としたWebサービスを作ることにしました。

ただ文章を投稿できるWebサービスはすでに世の中にたくさん出回っているため、差別化を図るべく文章を他者に閲覧してもらう時のフォントを、書き手側がある程度自由に選べるようにしたいと考えました。その機能を作り込む過程で、日本語Webフォントについての知見を多く得られたので、ここで紹介していきたいと思います。

# なぜWebフォントなのか？
システムフォントでWebサービスを利用することもできるのに、なぜWebフォントをあえて利用するのか？今回は、すでに述べたとおり競合サービスとの差別化という側面が大きかったものの、一般論としては以下のような理由で選択することが多いのではないか？と思います。

- 原則どの端末どのブラウザでも同じような表示が期待できる
- システムフォントよりも可読性の高いフォントを提供できる

特に可読性という点においては、後述のGoogle Fontsにて利用可能な「Noto Sans JP」は優れており、文字種も多いことから、日本語Webフォントの代表格と言って良いでしょう。

# Webフォント導入に際しての課題
一方、そのようなメリットのあるWebフォントですが、いくつかの課題があります。特にアルファベットのみの英語フォントと、漢字まで含んだ日本語フォントではファイルサイズに大きな差があり、後者の場合ページの表示速度を計測するPageSpeed Insightsのスコアはかなり苦しいものとなります。

従いまして、この点をどうチューニングするかがWebフォント提供元にとって重要となり、提供元ごとに導入方法が異なる要因にもなっています。あるいは提供元のそういった工夫に頼らず、フォントファイルを分割してセルフホスティングするという手間のかかる手段を選択することもあります。

またGoogle Fontsに関しては、フォントを提供する際に、IPアドレスやユーザーエージェントを収集している点が指摘されており、日本ではまだそこまで問題視されていないかもしれませんが、ドイツでは昨年[Google Fontsを利用することがGDPR違反であるとの判決](https://thehackernews.com/2022/01/german-court-rules-websites-embedding.html)が出て騒ぎとなり、その影響でPHPの人気フレームワークLaravelのデフォルトページから[Google Fontsを削除し、システムフォントを使うよう変更を加えています](https://github.com/laravel/framework/pull/40926)。

# Webフォントのプロバイダ
Webフォントのプロバイダとしては、すでに名前を挙げたGoogleが最有力です。ただし、Googleが提供するフォントサービス[Google Fonts](https://fonts.google.com/)は、便利な反面上述の通り、プライバシーへの配慮が海外で問題視されている点に留意する必要があります。それ以外の有力な選択肢としては、[Adobe Fonts](https://fonts.adobe.com/)があります。こちらは、Adobeのアカウントさえあれば無料でかなりの種類の日本語Webフォントを利用できる上(6割ぐらいはGoogleと被っていそう)、Adobeのいずれかの有償プランと契約することで、さらに多くのフォントを利用できるようになります。

その他の選択肢としては、モリサワフォントでお馴染みの株式会社モリサワが提供する[TypeSquare](https://typesquare.com/ja/)や、筑紫シリーズといった人気かつ高品質なフォントを数多く提供する[FONTPLUS](https://fontplus.jp/)などがあります。

今回は、Google FontsとAdobe Fontsの導入経験しかないので、TypeSquareやFONTPLUSについては割愛します。ただ、いずれも独自かつ高品質なフォントが多く揃っているので、特に競合するサイトとの差別化を図ったり、ページ全体のデザインを際立たせる用途では、非常に魅力的な選択肢だと思います。

# プロバイダごとのフォント導入のイロハ
## Google Fonts
Google Fontsのポータルから気になるフォントを選ぶと、HTMLに埋め込むためのコードが生成されるので、それをコピペして利用することになります。

パフォーマンスへの配慮として、ターゲットリソースへの事前接続ができるようpreconnect用のメタタグが生成したコードに付随しており、さらに「display=swap」クエリによりフォントをダウンロードするまでは代替フォントを表示するようになっています。また、オプションとしてtextクエリで使用する文字種を指定することができるため、見出しやロゴなどの短文だけ本文とは異なるフォントを使いたい場合に、パフォーマンスへの追加の影響を最小限にとどめることができます。
```html
//デフォルト
<link href="https://fonts.googleapis.com/css2?family=Noto+Serif+JP:wght@200&display=swap" rel="stylesheet">

//文字種を指定する(以下は「これは見出し」という文字種だけ指定)
<link href="https://fonts.googleapis.com/css2?family=Noto+Serif+JP:wght@200&display=swap&text=これは見出し" rel="stylesheet">
```

### Cloudflare Fonts
この名前、かなり紛らわしくCloudflareもWebフォントを提供してくれるのかと誤解を生みそうですが、実際はGoogle Fontsのパフォーマンスを改善してくれる機能です。[今年の10月にベータ版がリリースされたばかりで、日本ではまだ利用例は少ないと思います](https://blog.cloudflare.com/cloudflare-fonts-enhancing-website-privacy-speed/)。

仕組みとしては、Google FontsのリソースをあらかじめCloudflareにキャッシュしておくことで、セルフホスティングに近い形でフォントを提供することができるというものです。日本語フォントの場合、パフォーマンスを低下の要因としてファイルサイズにばかり目が行きますが、実際のところフォントを取得するまでの通信のオーバーヘッドも大きなマイナス要因になっているのが実情です。このため、本機能を導入することで期待以上の改善効果を得られる場合もあります。実際私が個人開発したサービスで試してみたところ、スコアが61から75に改善しました。他の方の報告では、スコアが30以上改善するケースもありました。
![](https://storage.googleapis.com/zenn-user-upload/8d7d4c2249b0-20231221.png)
![](https://storage.googleapis.com/zenn-user-upload/5d56eb2fd306-20231221.png)

ちなみに、Next.jsだと、[Font Optimization](https://nextjs.org/docs/pages/building-your-application/optimizing/fonts)という仕組みがあり、これが有効な場合は、Cloudflare Fontsを導入しても改善幅はわずかとなる可能性がありそうです。

導入は至って簡単で、以下の通りパフォーマンスの設定ページから機能を有効にするだけです。まだベータ版という点が気にはなるものの、すでにCloudflareを利用しているなら気軽に試すことができます。
![](https://storage.googleapis.com/zenn-user-upload/56b6e969f50c-20231221.png)

さらに海外で懸念されていたプライバシーへの配慮に関しても、本機能を利用すれば改善できるため、今後Google Fontsを利用する際には漏れなくセットで導入したいところです。

## Adobe Fonts
Adobe Fontsのポータルからログインし、好きなフォントを選んで「Webプロジェクト」に登録し、「Webプロジェクト」が生成するJavaScriptをサイトにコピペすることで使用できます。

このJavaScriptは、公式の説明によるとページ内で読み込む文字種だけをリクエストするため、日本語のようなマルチバイト対応のフォントでは、[読み込み時間に大きな影響を与えずに読み込むことが可能](https://helpx.adobe.com/jp/fonts/using/dynamic-subsetting.html)と謳っています。
```js
<script>
  (function(d) {
    var config = {
      kitId: 'xxxx',
      scriptTimeout: 3000,
      async: true
    },
    h=d.documentElement,t=setTimeout(function(){h.className=h.className.replace(/\bwf-loading\b/g,"")+" wf-inactive";},config.scriptTimeout),tk=d.createElement("script"),f=false,s=d.getElementsByTagName("script")[0],a;h.className+=" wf-loading";tk.src='https://use.typekit.net/'+config.kitId+'.js';tk.async=true;tk.onload=tk.onreadystatechange=function(){a=this.readyState;if(f||a&&a!="complete"&&a!="loaded")return;f=true;clearTimeout(t);try{Typekit.load(config)}catch(e){}};s.parentNode.insertBefore(tk,s)
  })(document);
</script>
```
実際、そのおかげかFCP（First Contentful Paint）のスコアは良好でした。ただしLCP(Largest Contentful Paint)のスコアは悪く、Google Fontsで同じフォントを読み込んだ場合と比べると、Adobe Fontsのスコアは若干低くなりました。

また、複数の種類のフォントを提供する場合、Adobe公式のセオリーに則って、「Webプロジェクト」にそれらのフォントを登録して使用すると、LCPがさらに悪化するほか、バックグラウンドで数十MBの通信が行われるため、毎月のデータ量に制限があるプランを選択しているスマホユーザーには疎まれる可能性が高いだろうと思います。

パフォーマンス以外の留意点としては、クライアントのサイトにAdobe Fontsを導入する場合には、クライアントが契約したAdobeのアカウントから「Webプロジェクト」を作成してもらい、そこから[フォントを配信する必要](https://helpx.adobe.com/jp/fonts/using/font-licensing.html#web-client)があり、Google Fontsほどお手軽とは言えないかもしれません。


# 細かすぎるWebフォントの辛み
基本的には、上記で挙げたプロバイダを決めて生成されるコードを自サイトに取り込めば、導入は完了となるはずです。しかし一部のユースケースではまだ不十分な場合があります。明朝体を利用するケースとルビを利用するケース、この二つのケースでは以下に挙げる細かい対策が必要です。

## 明朝体は辛いよ
一般的なWebサイトで選択されるフォントは、おそらくゴシック体だと思います。ただ文章そのものをメインコンテンツとする場合には、ゴシック体の他、明朝体も提供したいというニーズも出てきます。フォントを表示する際は、フォントスムージング（アンチエイリアス）により明朝体でも滑らかな表示が期待できますが、Windowsに限っては、このフォントスムージングが機能しないため、ゴシック体ならいざ知らず明朝体は最悪かすれて読めない可能性もあります。実際個人開発のサービスでは、リリース後にユーザーさんからそのような指摘をいただいております。

一応CSSには、font-smoothというプロパティがあったのですが、[MDNでは「非標準」となっています](https://developer.mozilla.org/ja/docs/Web/CSS/font-smooth)。結果、CSSを使って人の目では気づかない微小の傾きをフォントに加えるというテクニックを採用することになります。なぜ傾きを加えるかというと、Windowsではフォントが傾いている場合に限り、フォントスムージングが有効になる仕様だからです。具体的には以下のようなコードを追加します。
```css
.windows-font {
    transform: rotate(0.03deg);
}
```

## 文字とルビの隙間はフォントによって異なる
日本語の文章の場合、ルビが必要になることがあります。このルビ、どのフォントを使用しても本文との間隔は一定であることを期待するのですが、実際はフォントによってバラバラです。場合によっては、間隔が空きすぎて行間が間延びすることさえあります。このためある程度の微調整を行う必要が出てきます。今回も先ほど傾きを加える際に使用したtransformで制御することができます。
```css
.ruby {
	transform: translateY(-0.1rem);
}
```

# まとめ
今回、日本語Webフォントを利用するにあたって情報を集めてみましたが、Google Fonts以外の情報はほとんどなく、国内においてWebフォントの利用はあまり進んでいないように感じました。

ただ、今年発表されたCloudflare Fontsは、Google限定とはいえパフォーマンスやプライバシーの問題を改善してくれるため、今後はWebフォントを活用する機会は増えていくだろうと予想します。エンジニアとしてしっかり情報をキャッチアップし、必要な時に適切に導入できるよう情報収集や検証を続けて行きたいと思います。