ADR-0075: 本文をシステムフォントで描き、Web フォントを記事の題と見出しの明朝と等幅だけにする¶
Status¶
承認
Context¶
和文の書体の読み込みを減らすために、本文の書体と、Web フォントの配信の方法を決め直す必要がある。
- サイトの基盤の要求は、Lighthouse の Performance が 90 以上、LCP が 2.5 秒以内である。条件は Moto G Power、Slow 4G 相当である。
- トップを 2 回目以降に訪問したときは、Performance が 75、LCP が 5.71 秒で、要求に届かない(simulate、5 回の中央値)。
- LCP の要素は、庭の和紙に置いたプロフィールの段落である。この段落は、本文の書体の Noto Sans JP で描かれる。
- トップは、Noto Sans JP の分割を 28 ファイル、352 KiB 取得する。
- レンダリングを妨げる CSS は gzip で 179 KiB あり、ほぼ全部が 632 件の
@font-faceである。Noto Sans JP の 400 と 700 が、そのうち 248 件を占める。
- 運営者は、和の感じを残すと決めた。書体は変えてよいとした。
- DADS の書体は Noto Sans JP と Noto Sans Mono で、選んだ理由は可読性と視認性の高いサンセリフであることである。システムの書体を使うことは制限していない。
- 出典: DADS のタイポグラフィ
- 本文には、
PostgreSQL、EXPLAIN、Buffersのような欧文の技術用語が、ほぼ全ての段落に出てくる。欧文の字の大きさと線の太さが和文とずれると、技術用語だけが小さく薄く見える。 - Fontsource の STIX Two Text は、roman と italic の woff2 を合わせて 263 KiB あり、latin の分割だけで 58 KiB ある。
- Zen Old Mincho は、仮名の重心が現代の明朝より低いオールドスタイル明朝である。起筆と終筆に筆意は残るが、活字なので筆文字に当たらない。
- 和文の可変の書体は、1 つの分割がウェイトの軸を持つので重い。Noto Serif JP の可変は、1 つの分割が平均 56 KB だった。Zen Old Mincho の静的なウェイトは、1 つの分割が平均 20 KB だった。
- プレイグラウンドの Node の実行環境のパスと、それを埋め込む記事の URL は、
COEP: require-corpを返す。COEP の下では、CORP を返さないクロスオリジンのリソースがブロックされる。 - 書体の CSS(
packages/ui/src/tokens/fonts.css)は、apps/web、apps/playground、packages/ui の Storybook が読む。 - apps/web のビルドは、記事の題と見出しに使う Zen Old Mincho の分割を、使う字だけに作り直す(
apps/web/src/lib/subset-fonts.ts)。apps/playground と Storybook のビルドは、作り直さない。 - Fontsource の Noto Sans JP は、unicode-range の分割と、和文の字をまとめたウェイトごとの 1 ファイル(1.1〜1.2 MiB)を持つ。サイトで使う字だけのファイルは持たない。
Decision¶
本文の和文と欧文を、システムフォントで描く。
Web フォントは、記事の題と見出しの明朝と、等幅だけにする。
本文の Web フォントの取得をなくすと、トップの Performance が simulate の中央値で 90 に届いたためである。
| 役割 | 書体 | ウェイト | 配信の方法 |
|---|---|---|---|
| 本文 | システムフォント。"Hiragino Sans", "Hiragino Kaku Gothic ProN", "Yu Gothic", Meiryo, "Noto Sans CJK JP", sans-serif |
400 / 700 | 読み込まない |
| 記事の題と見出し | Zen Old Mincho。代替は本文の font-family の書体 |
600 | Fontsource の分割を self-host し、ビルドで使う字だけに作り直す |
| 等幅 | Noto Sans Mono | 400 / 700 | Fontsource の分割を self-host する |
| 等幅の中の和文 | BIZ UDGothic | 400 / 700 | Fontsource の分割を self-host する |
- 本文の
font-familyの値は、Verification の計測に使った値で始める。Windows と Android の端末で、本文がどの書体で描かれるかと記事のページの見た目を確認し、確認の結果で、font-familyに並べる書体と順を直す。どの書体も無い端末は、ブラウザのsans-serifで描く。 - 本文の
font-familyの値は、プリミティブトークンの--fd-primitive-font-family-sansの 1 か所に置く。テーマ変数の--font-sansはこの値を参照し、--font-headingは代替の書体としてこの値を参照する。 - 本文と見出しに、欧文だけに使う Web フォントを足さない。
- 欧文の Web フォントを足すと、本文で Web フォントを取得することになるためである。
- 本文の欧文は、システムフォントの和文の書体が持つ Latin で描く。和文の書体が持つ Latin は、大きさと太さが和文とそろう。
- 記事の題と見出しの欧文は Zen Old Mincho が持つ Latin で、等幅の欧文は Noto Sans Mono で描く。
- 和の感じは、記事の題と見出しの明朝で残す。主の色で和の感じを残す判断は ADR-0024 に、挿絵で残す判断は ADR-0026 にある。
- 和文の Web フォントに、可変の書体を使わない。和文の Web フォントは書体ごとに 1 つか 2 つのウェイトしか使わないので、ウェイトの軸の分だけ転送量を増やす理由がない。
- Web フォントは Fontsource で self-host し、外部の CDN から読まない。同一オリジンから配信すれば、COEP の下でもサードパーティのヘッダの方針に左右されない。
- どの Web フォントも
font-display: swapにし、和文の分割は preload しない。 size-adjustは使わない。本文は Web フォントを読み込まないので、本文では差し替えのずれが起きないためである。
Verification¶
トップを 2 回目以降に訪問したときの値を、pnpm run measure:top で測った(Metal、mobile、simulate、各案 5 回)。
対象は develop の 5825f0e に、案ごとの実験の変更を当てたものである。
システムフォントの案は、Decision の表の本文の font-family で測った。
本文は macOS の Hiragino Sans で描かれた。
| 案 | Performance(中央値と範囲) | LCP(中央値) | FCP(中央値) | フォントのリクエスト | フォントの転送量 | CSS の転送量 |
|---|---|---|---|---|---|---|
| システムフォント | 92(88〜92) | 2.86 s | 1.50 s | 6 | 34 KiB | 112 KiB |
| サブセット(1 ファイル) | 89(85〜89) | 3.30 s | 1.50 s | 8 | 124 KiB | 112 KiB |
| サブセット(分割のまま) | 82(80〜82) | 4.21 s | 1.80 s | 34 | 143 KiB | 179 KiB |
| 今の構成 | 75(70〜92) | 5.71 s | 1.80 s | 34 | 386 KiB | 179 KiB |
- サブセットの 2 つの案は、サイトで使う 291 字だけのファイルで測った。
- サブセット(1 ファイル)の案は、google/fonts の Noto Sans JP の可変の書体を 400 と 700 に固定し、pyftsubset のデフォルトの layout の feature で作った。1 ファイルは 44〜45 KiB だった。layout の feature を全て残すと、1 ファイルが 68〜70 KiB になり、Performance は 87 だった。
- 今の構成で Performance が 92 になった 1 回は、庭の WebGL の最初のフレームがページの最初の描画に入り、LCP が FCP と同じ 2.71 秒になった回である。
- devtools のスロットリングで 6 回ずつ測った。
- システムフォントの案は、Performance が 80〜82、LCP が 3.56〜3.61 秒、TBT が 240〜281 ms だった。
- 今の構成は、4 回が Performance 79〜84、LCP 3.42〜3.86 秒、TBT 0 ms だった。2 回は load が 7.3〜7.4 秒まで延び、Performance 53 と 58、LCP 7.35〜7.46 秒だった。
- システムフォントの案に、load が延びる回は無かった。
- どの案も、LCP の 2.5 秒には届かなかった。
- 合否に使う測り方(GPU とスロットリング)は、運営者が決める。
- 最初の訪問、記事のページ、Windows と Android の端末は測っていない。
Considered Options¶
| 選択肢 | 強み | 弱み |
|---|---|---|
| 採用: 本文をシステムフォントにする | 測った 4 つの案で唯一、Performance が simulate の中央値で 90 に届いた(92)。本文の字が増えても、取得する量が変わらない。変えるのは、プリミティブトークンと fonts.css、生成したトークン、依存 1 つだけで、apps/web、apps/playground、Storybook に同じ変更が入る |
本文の字形が端末ごとに違う。DADS の Noto Sans JP から外れる。字の幅と行の折り返しが端末ごとに変わる |
| Noto Sans JP を、サイトで使う字だけのウェイトごとの 1 ファイルにする(サブセット(1 ファイル)の案) | 字形がどの端末でも同じになる。Performance が 75 から 89 に上がった | Performance は 89 で、90 に届かない。記事が増えて字が増えると、ファイルが大きくなる。apps/playground と Storybook にも、作り直す処理が要る。訪問者が入力した、ファイルに無い字は別の書体で描かれる |
| Noto Sans JP の分割を残し、各分割を使う字だけにする(サブセット(分割のまま)の案。見出しの明朝と同じ処理) | 見出しの明朝の処理をそのまま使える | Performance は 82 で、90 に届かない。リクエストの数と、レンダリングを妨げる CSS の @font-face が減らない |
| 今の構成(Noto Sans JP の分割をそのまま配信する) | DADS と同じ書体で、字形がどの端末でも同じになる | Performance が 75、LCP が 5.71 秒で、要求に届かない |
| BIZ UD の一族でそろえる(本文 BIZ UDPGothic、見出し BIZ UDPMincho) | 本文、見出し、等幅の字形がそろう | 和の感じが弱い。本文の Web フォントの取得が残り、今の構成と同じ理由で要求に届かない見込みである(測っていない) |
| 欧文に STIX Two Text を足す | x-height と線の太さが和文に近く、技術用語が和文と同じ大きさと太さで読める | 本文で Web フォントを取得することになる。latin の分割だけで 58 KiB ある |
| 本文も明朝(Zen Old Mincho) | 和の感じが最も強い | 本文の字が多く、読み込む量が最も大きい。DADS がサンセリフを選んだ理由とも合わない |
Consequences¶
Positive¶
- 本文の Web フォントの取得がなくなり、レンダリングを妨げる CSS が gzip で 179 KiB から 112 KiB に減る。トップの FCP は 1.80 秒から 1.50 秒になった。
- 代替の書体から差し替わるときのずれが、本文で起きない。
- 記事のページも、本文の Web フォントを取得しなくなる。記事のページの値は測っていない。
Negative¶
- 本文の見た目が、端末に入っている書体ごとに変わる。Hiragino Sans、Yu Gothic、Meiryo、Noto Sans CJK JP のどれで描くかで、字の幅、行の折り返し、太さが違う。
- DADS の書体から、本文も外れる。DADS のコンポーネントの見た目は、システムフォントで描いた状態で確認する。
- 記事の題と見出しは、Zen Old Mincho が読み込まれるまで本文の
font-familyの書体で描かれ、読み込まれた後に明朝へ差し替わる。size-adjustを使わないので、差し替わるときに字の幅と行の折り返しがずれる。 - 欧文の字形と大きさが、端末に入っている和文の書体ごとに変わる。
- LCP の 2.5 秒には、この決定だけでは届かない。2.5 秒を超える分は、庭のバンドルの取得によると推測する。
- レンダリングを妨げる CSS には、見出しの明朝と等幅の
@font-faceが 384 件残る。 - 見た目の回帰テストでは、スクリーンショットの本文が、テストを実行する環境に入っている書体で描かれる。