ハコヅミを作る #21:画面のフォントを、丸ゴシックの Web フォントにする

#19でタイトルバナーとロゴを入れてから、気になることが出てきました。ロゴやアイコンは丸みのある絵なのに、画面の文字は端末の標準のフォントのままで、雰囲気が合っていません。

今回は、画面のフォントを変えます(#102)。


最初の案は「Mac は M PLUS 1p、Windows は MS UI ゴシック」

/issue に渡したメモは、こうでした。

フォントを Mac 用に「M PLUS 1p」とし、Windows でこのフォントが使用できないのであれば「MS UI ゴシック」にする。フォントの選定としてこの仕様はどうだろう?意見をちょうだい

Claude Code からは、Issue の下書きの前に、3つの指摘が返ってきました。

  • M PLUS 1p は、Mac にも最初からは入っていない。OS に付いてくるフォントではないので、CSS にフォント名を書くだけでは、入れていない端末では出ない。確実に出すには、Web フォントとして配る必要がある
  • 一番使う場面は、スマホ。積み込みながら使うアプリなので、Mac と Windows だけを決めても、iPhone と Android が抜ける
  • MS UI ゴシックは、おすすめしない。古い時代の画面用フォントで、今の画面では粗く見える。読み込めなかったときの代わりは、今の設定(端末の標準のフォント)のままが無難

「Mac 用」「Windows 用」と考えていたこと自体が、ずれていました。Web フォントにすれば、どの端末でも同じフォントで出るので、OS で分ける必要がありません。

これまで使っていた設定は、#11でデザイントークンを作ったときの「端末に入っているもの(後で見直す可能性あり)」のままでした。その「後で」が来たわけです。


同じ画面で、3つを見比べる

もう1つ、提案がありました。ロゴに合わせるなら、同じ系統の丸ゴシック M PLUS Rounded 1c もある、というものです。

名前を聞いても違いは分からないので、同じ画面を3つのフォントで撮って、並べてもらいました。

ギアの一覧の同じ部分を、3つのフォントで出したもの。上から、今のフォント(端末のフォント)、M PLUS 1p、M PLUS Rounded 1c。下の2つは骨格が同じで、M PLUS Rounded 1c は線の端が丸い

上から、今のフォント/M PLUS 1p/M PLUS Rounded 1c。原寸に近い拡大

持ち物チェックの画面を、3つのフォントで横に並べたもの。左から、今のフォント、M PLUS 1p、M PLUS Rounded 1c。行の折り返しの位置は、3つともほぼ同じ

持ち物チェックの画面での見比べ(左から、今/M PLUS 1p/M PLUS Rounded 1c)。押すと大きく開きます

画面は、手元でアプリを動かし、開いたページにフォントの設定を仮に当てて撮ったものです。コードは変えていません。データは#7で Notion から取り込んだ実際のギアです。

並べてみて分かったことがあります。

  • 2つの M PLUS の違いは、思ったより小さい。骨格は同じで、違うのは線の端が丸いかどうかだけ。メーカーのバッジのような小さい文字では、ほとんど見分けがつかない。違いが出るのは、見出しやボタンの大きな太字
  • 太字が、今より太くなる。今の見出しは「やや太い」(600)だが、M PLUS にはその太さがなく、次に太い 700 で出る
  • かなが少し広い。1行が少し長くなる。ただ、長い製品名が折り返す位置は、3つともほぼ同じで、崩れるところはなかった

見比べたうえで、ロゴやアイコンと雰囲気がそろう M PLUS Rounded 1c に決めました。最初のメモの M PLUS 1p ではありません。画像がなければ、最初の案のまま進めていたと思います。


読み込み方

フォントは Google Fonts から読み込みます。アプリの中にフォントのファイルを入れて配る方法もありますが、日本語のフォントは大きく、分割して入れる手間がかかります。まずは手軽なほうにしました。

変えたのは2か所だけです。

/* src/app.css:デザイントークンの先頭に足す。うしろは今までの端末のフォント */
--font-sans:
	'M PLUS Rounded 1c', system-ui, -apple-system, 'Hiragino Sans', 'Hiragino Kaku Gothic ProN',
	'Noto Sans JP', 'Yu Gothic UI', Meiryo, sans-serif;
<!-- src/app.html -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
	rel="stylesheet"
	href="https://fonts.googleapis.com/css2?family=M+PLUS+Rounded+1c:wght@400;500;700&display=swap"
	media="print"
	onload="this.media = 'all'"
/>

ページや部品には、フォント名を書いていません。色と同じく、トークンの1か所を変えるだけで、全部の画面に効きます。

電波の弱い場所で、画面が止まらないようにする

気をつけたのは、Google Fonts に届きにくいときです。ハコヅミを開くのは、自宅の駐車場だけではありません。電波の弱いキャンプ場で、持ち物やキャンプ場の情報を見ることもあります。

スタイルシートをふつうに読み込むと、ブラウザは、その読み込みが終わるまで画面を描きません。フォントの設定が届くのを待っている間、画面そのものが真っ白になります。

そこで、上の media="print" と onload の組み合わせを使いました。

  • media="print":「印刷用」のスタイルシートとして読み込む。画面の表示には使わないので、ブラウザは待たずに画面を描く
  • onload="this.media = 'all'":読み込みが終わったら、画面用に切り替える
  • display=swap:フォントのファイルが届くまでは、端末のフォントで文字を出す

届かなければ、端末のフォントのままで、今までどおり使えます。その代わり、最初に開いたときは、端末のフォントで出たあとに M PLUS Rounded 1c に切り替わるので、一瞬だけ文字の形が変わります。


E2E を、外のサービスから切り離す

フォントを外から読み込むようにすると、E2E のブラウザからも、Google Fonts への通信が出ます。Google の調子や CI のネットワークで、テストが遅くなったり落ちたりするのは避けたいところです。

Playwright のブラウザの起動の設定で、Google Fonts のホスト名を「見つからない」ことにしました。

// playwright.config.ts
use: {
	launchOptions: {
		args: [
			'--host-resolver-rules=MAP fonts.googleapis.com ~NOTFOUND, MAP fonts.gstatic.com ~NOTFOUND'
		]
	}
}

これで、E2E は Google Fonts に一切届きません。副産物として、150件ある E2E のすべてが、「フォントを読み込めなくても使える」ことの確認を兼ねるようになりました。

ただし、裏返すと、E2E では実際のフォントの見た目は確かめられません。確かめているのは、次の2つだけです。

  • フォントの指定の先頭が M PLUS Rounded 1c になっていること(入力欄・ボタン・選択欄も)
  • 読み込みに失敗しても、画面が出て、操作できること

実際の見た目は、手元でフォントを読み込んだ状態の画面を撮って、目で確かめました。3つの太さ(400・500・700)が読み込まれていることも、ブラウザに聞いて確かめています。

M PLUS Rounded 1c にしたキャンプの画面。見出し、キャンプ情報、持ち物チェックの文字が、丸ゴシックで出ている

M PLUS Rounded 1c にしたキャンプの画面


おわりに

  • 「Mac 用」「Windows 用」で分けるのではなく、Web フォントで全部の端末を同じにする
  • フォントは、同じ画面で並べて決める。名前や見本だけでは分からない
  • スタイルシートは、届かなくても画面が止まらない形で読み込む
  • E2E は外のサービスから切り離す。そのぶん、見た目は目で確かめる

Google Fonts を使うと、画面を開くたびに Google のサーバーへ通信が出ます。今は自分しか使わないので問題ありませんが、公開するときには、プライバシーポリシーに書く必要があります。電波のない場所で確実に出したくなったら、フォントのファイルをアプリの中に入れる形に変えるつもりです。

次回は、見出しと一覧の見た目を直した話です。

← トップページに戻る