「Web フォント」を使って OS 依存しない日本語対応の等幅フォント Noto Sans Mono CJK JP を適用する

最近の Windows と Mac は、「游ゴシック体」という同一のサンセリフ・フォントを標準搭載するようになった。メイリオとヒラギノ、MS P ゴシックと Osaka のように、OS ごとに標準フォントが異なり、ウェブサイトの見栄えが OS によって異なってしまう問題を最小限にできるようになってきた。游ゴシック体の適用方法については以前から数回記事を書いてきた。

一方、このサイトは技術ブログであり、コードを掲載する機会も多いので、等幅フォントについても気を使う。コード内のコメントには日本語を使うので、日本語文字を有する等幅フォントで、OS 間で差異がない (少ない) モノをずっと探してきた。残念ながら、Windows は MS ゴシックくらいしかなく、Mac も Osaka-等幅 くらいしか持っていない。

個人的には、Windows にも Mac にも、「MeiryoKe」というメイリオベースの等幅フォント (ツールを使って各自の環境で生成する) と、「Ricty Diminished」というフリーのフォントを必ず入れるようにしており、メインは MeiryoKe を使っている。そしてこれらのフォントを CSS で必ず指定するようにしているのだが、コレが有効になるのは、サイトを閲覧する PC に当該フォントがインストールされている場合のみだ。コレでは自分以外のユーザの環境では意図したフォントが保てない。

そこで今回は、Web フォントという技術を利用して、Google が提供する「Noto Sans Mono CJK JP」というフリーのフォントを適用する方法を紹介する。

目次

Web フォントとは

Web フォントとは、ウェブサイト側からフォントファイルを提供し、クライアント側はそれをダウンロードしてレンダリングをする仕組みであり、それに対応した形式のフォントのことである。

Web フォントに利用できる形式はいくつかあるが、一番広く利用できるのが WOFF2 および WOFF で、古いブラウザ向けに TTF (TrueType) や EOT (Embedded Open Type) を用意できる。OTF (OpenType) も利用可能だ。

Web フォントを定義するには、CSS で @font-face ルールを使って font-family を新規に定義する。src プロパティにクライアント側のシステムローカルからフォント取得を試みる local() を指定するか、ウェブ上にあるフォントファイルの URL を指定してダウンロードさせる url() を指定する。

「クライアントにフォントファイルをダウンロードさせる」という仕組みであるため、文字数が多い日本語のフォントとなると、15〜20MB 程度のファイルサイズになる。当然ダウンロードからレンダリングまでには時間がかかるため、多くの環境で FOIC (Flash Of Invisible Content) や FOUC (Flash Of Unstyled Content) といった問題が起こる。コレを軽減するには、フォントファイルを生成する際に使用する文字を削る「サブセット化」などを行う必要がある。

@font-face ルール自体は、游ゴシック体の表示調整のために利用したことがあったが、WOFF ファイルなどを用意して Web 上からフォントファイルをダウンロードさせるのはやったことがなかったので、今回初。早速やってみようと思う。

元となる OTF ファイルをダウンロードする

まずは以下の Google のサイトより、Noto Sans CJK JP フォントのパッケージ NotoSansCJKjp-hinted.zip をダウンロードする。

この中には、複数のウェイトのフォントファイルが含まれているが、殆どはサンセリフ体のフォント。等幅フォントなのは、この内

の2ファイルだけ。このファイルを取り出す。

WOFF 形式に変換する

次に、この OTF 形式のファイルを、Web フォントとして最適化された形式である WOFF 形式に変換する。「WOFF コンバータ」というツールで、.woff.woff2 形式に書き出せる。

生成は1ファイルごとで、数分かかった。以下の4ファイルが生成できれば OK。

OTF ファイルからは EOT ファイルを生成できなかったので、EOT は諦めた。

CSS を準備する

こうして用意したフォントファイルを読み込んで利用できるようにするため、サンプルページを作り、CSS を作り込んでいくことにする。このような作業ディレクトリを用意しよう。

【任意の作業ディレクトリ】
├ test.html … サンプルページ (CSS はインラインの style 要素内に書く)
├ NotoSansMonoCJKjp-Regular.woff2
├ NotoSansMonoCJKjp-Regular.woff
├ NotoSansMonoCJKjp-Regular.otf
├ NotoSansMonoCJKjp-Bold.woff2
├ NotoSansMonoCJKjp-Bold.woff
└ NotoSansMonoCJKjp-Bold.otf

test.html には style 要素を用意し、以下のようにコーディングする。

@font-face {
  font-family: "Noto Sans Mono CJK JP";
  font-weight: 100;
  src: local("NotoSansMonoCJKjp-Regular"),
       local("Noto Sans Mono CJK JP Regular"),
       url("./NotoSansMonoCJKjp-Regular.woff2") format("woff2"),
       url("./NotoSansMonoCJKjp-Regular.woff")  format("woff"),
       url("./NotoSansMonoCJKjp-Regular.otf")   format("opentype");
}
@font-face {
  font-family: "Noto Sans Mono CJK JP";
  font-weight: 200;
  src: local("NotoSansMonoCJKjp-Regular"),
       local("Noto Sans Mono CJK JP Regular"),
       url("./NotoSansMonoCJKjp-Regular.woff2") format("woff2"),
       url("./NotoSansMonoCJKjp-Regular.woff")  format("woff"),
       url("./NotoSansMonoCJKjp-Regular.otf")   format("opentype");
}
@font-face {
  font-family: "Noto Sans Mono CJK JP";
  font-weight: 300;
  src: local("NotoSansMonoCJKjp-Regular"),
       local("Noto Sans Mono CJK JP Regular"),
       url("./NotoSansMonoCJKjp-Regular.woff2") format("woff2"),
       url("./NotoSansMonoCJKjp-Regular.woff")  format("woff"),
       url("./NotoSansMonoCJKjp-Regular.otf")   format("opentype");
}
@font-face {
  font-family: "Noto Sans Mono CJK JP";
  font-weight: 400;
  src: local("NotoSansMonoCJKjp-Regular"),
       local("Noto Sans Mono CJK JP Regular"),
       url("./NotoSansMonoCJKjp-Regular.woff2") format("woff2"),
       url("./NotoSansMonoCJKjp-Regular.woff")  format("woff"),
       url("./NotoSansMonoCJKjp-Regular.otf")   format("opentype");
}
@font-face {
  font-family: "Noto Sans Mono CJK JP";
  font-weight: 500;
  src: local("NotoSansMonoCJKjp-Regular"),
       local("Noto Sans Mono CJK JP Regular"),
       url("./NotoSansMonoCJKjp-Regular.woff2") format("woff2"),
       url("./NotoSansMonoCJKjp-Regular.woff")  format("woff"),
       url("./NotoSansMonoCJKjp-Regular.otf")   format("opentype");
}
@font-face {
  font-family: "Noto Sans Mono CJK JP";
  font-weight: 600;
  src: local("NotoSansMonoCJKjp-Regular"),
       local("Noto Sans Mono CJK JP Regular"),
       url("./NotoSansMonoCJKjp-Regular.woff2") format("woff2"),
       url("./NotoSansMonoCJKjp-Regular.woff")  format("woff"),
       url("./NotoSansMonoCJKjp-Regular.otf")   format("opentype");
}
@font-face {
  font-family: "Noto Sans Mono CJK JP";
  font-weight: 700;
  src: local("NotoSansMonoCJKjp-Bold"),
       local("Noto Sans Mono CJK JP Bold"),
       url("./NotoSansMonoCJKjp-Bold.woff2") format("woff2"),
       url("./NotoSansMonoCJKjp-Bold.woff")  format("woff"),
       url("./NotoSansMonoCJKjp-Bold.otf")   format("opentype");
}
@font-face {
  font-family: "Noto Sans Mono CJK JP";
  font-weight: 800;
  src: local("NotoSansMonoCJKjp-Bold"),
       local("Noto Sans Mono CJK JP Bold"),
       url("./NotoSansMonoCJKjp-Bold.woff2") format("woff2"),
       url("./NotoSansMonoCJKjp-Bold.woff")  format("woff"),
       url("./NotoSansMonoCJKjp-Bold.otf")   format("opentype");
}
@font-face {
  font-family: "Noto Sans Mono CJK JP";
  font-weight: 900;
  src: local("NotoSansMonoCJKjp-Bold"),
       local("Noto Sans Mono CJK JP Bold"),
       url("./NotoSansMonoCJKjp-Bold.woff2") format("woff2"),
       url("./NotoSansMonoCJKjp-Bold.woff")  format("woff"),
       url("./NotoSansMonoCJKjp-Bold.otf")   format("opentype");
}

/* ↓ 利用箇所にはこのように指定すれば OK */
.noto-sans-mono-cjk-jp {
  font-family: "Noto Sans Mono CJK JP";
}

コレは何をしているかというと、@font-faceNoto Sans Mono CJK JP という名前のフォントを定義していて、font-weight の値ごとに Regular フォントと Bold フォントの指定を分けているのだ。このように、@font-facefont-weight 等の指定に応じて異なるフォントを指定したりできる。

最後に、このフォントを使う場所を指定できるよう、.noto-sans-mono-cjk-jp というテスト用の CSS クラスを定義した。この CSS クラスを適当な要素に振り、サンプルページの表示を確認してみよう。同ディレクトリにある NotoSansMonoCJKjp-Regular.woff2 などを参照して、Noto Sans Mono CJK JP フォントで表示できていることだろう。

一応、クライアントローカルに同じフォントがインストール済みであれば、余計なダウンロードをしなくて済むよう、ローカルフォントを使用させる設定も書いている。しかしこの設定はイマイチ効きが良くなかった。

よって、local() 指定は Mac 向けに「PostScript 名」表記のみすれば良いが、上手く認識される可能性がある「正式名称」を念のために併記し、それから Web フォントを読み込ませる順序が最適と考える。そういうワケで、以下の書き方でウェイト別に定義しておくのが良い、という結論に至った。

@font-face {
  font-family: "Noto Sans Mono CJK JP";
  font-weight: 400;                             /* 400 = normal・700 = bold */
  src: local("NotoSansMonoCJKjp-Regular"),      /* PostScript 名 の表記 : Mac で有効 */
       local("Noto Sans Mono CJK JP Regular"),  /* 正式名称 の表記 : Windows・Mac ともに無効だったものの一応記載 */
       url("./NotoSansMonoCJKjp-Regular.woff2") format("woff2")   ,  /* WOFF2 形式の Web フォント (変換生成したモノ) */
       url("./NotoSansMonoCJKjp-Regular.woff")  format("woff")    ,  /* WOFF  形式の Web フォント (変換生成したモノ) */
       url("./NotoSansMonoCJKjp-Regular.otf")   format("opentype");  /* OTF   形式のフォント (DL したままのモノ) */
}

ココまでできたら、作業用ディレクトリごとどこかにアップロードすれば、無事 Web フォントを使用したサイトが構築できた。

Web フォントを CDN 配布してみる

せっかくココまで作ったので、Web フォントを CDN 配布してみることにした。この作業用ディレクトリに近いモノを npm で公開し、unpkg.org や jsdelivr.com などの npm パッケージを CDN 配信してくれるサービスを利用してみることにした。

先程のコードでは、url("./NotoSansMonoCJKjp-Regular.woff2") というように相対パスだったが、コレを以下のように直せば、もう自分でフォントファイルを変換して用意しなくても良い。

@font-face {
  font-family: "Noto Sans Mono CJK JP";
  font-weight: 100;
  src: local("NotoSansMonoCJKjp-Regular"),
       local("Noto Sans Mono CJK JP Regular"),
       url("https://cdn.jsdelivr.net/npm/@japanese-monospaced-fonts/noto-sans-mono-cjk-jp@1.0.1/NotoSansMonoCJKJP-Regular.otf.otf") format("opentype");
}
@font-face {
  font-family: "Noto Sans Mono CJK JP";
  font-weight: 200;
  src: local("NotoSansMonoCJKjp-Regular"),
       local("Noto Sans Mono CJK JP Regular"),
       url("https://cdn.jsdelivr.net/npm/@japanese-monospaced-fonts/noto-sans-mono-cjk-jp@1.0.1/NotoSansMonoCJKJP-Regular.otf.otf") format("opentype");
}
@font-face {
  font-family: "Noto Sans Mono CJK JP";
  font-weight: 300;
  src: local("NotoSansMonoCJKjp-Regular"),
       local("Noto Sans Mono CJK JP Regular"),
       url("https://cdn.jsdelivr.net/npm/@japanese-monospaced-fonts/noto-sans-mono-cjk-jp@1.0.1/NotoSansMonoCJKJP-Regular.otf.otf") format("opentype");
}
@font-face {
  font-family: "Noto Sans Mono CJK JP";
  font-weight: 400;
  src: local("NotoSansMonoCJKjp-Regular"),
       local("Noto Sans Mono CJK JP Regular"),
       url("https://cdn.jsdelivr.net/npm/@japanese-monospaced-fonts/noto-sans-mono-cjk-jp@1.0.1/NotoSansMonoCJKJP-Regular.otf.otf") format("opentype");
}
@font-face {
  font-family: "Noto Sans Mono CJK JP";
  font-weight: 500;
  src: local("NotoSansMonoCJKjp-Regular"),
       local("Noto Sans Mono CJK JP Regular"),
       url("https://cdn.jsdelivr.net/npm/@japanese-monospaced-fonts/noto-sans-mono-cjk-jp@1.0.1/NotoSansMonoCJKJP-Regular.otf.otf") format("opentype");
}
@font-face {
  font-family: "Noto Sans Mono CJK JP";
  font-weight: 600;
  src: local("NotoSansMonoCJKjp-Regular"),
       local("Noto Sans Mono CJK JP Regular"),
       url("https://cdn.jsdelivr.net/npm/@japanese-monospaced-fonts/noto-sans-mono-cjk-jp@1.0.1/NotoSansMonoCJKJP-Regular.otf.otf") format("opentype");
}
@font-face {
  font-family: "Noto Sans Mono CJK JP";
  font-weight: 700;
  src: local("NotoSansMonoCJKjp-Bold"),
       local("Noto Sans Mono CJK JP Bold"),
       url("https://cdn.jsdelivr.net/npm/@japanese-monospaced-fonts/noto-sans-mono-cjk-jp@1.0.1/NotoSansMonoCJKJP-Bold.otf") format("opentype");
}
@font-face {
  font-family: "Noto Sans Mono CJK JP";
  font-weight: 800;
  src: local("NotoSansMonoCJKjp-Bold"),
       local("Noto Sans Mono CJK JP Bold"),
       url("https://cdn.jsdelivr.net/npm/@japanese-monospaced-fonts/noto-sans-mono-cjk-jp@1.0.1/NotoSansMonoCJKJP-Bold.otf") format("opentype");
}
@font-face {
  font-family: "Noto Sans Mono CJK JP";
  font-weight: 900;
  src: local("NotoSansMonoCJKjp-Bold"),
       local("Noto Sans Mono CJK JP Bold"),
       url("https://cdn.jsdelivr.net/npm/@japanese-monospaced-fonts/noto-sans-mono-cjk-jp@1.0.1/NotoSansMonoCJKJP-Bold.otf") format("opentype");
}

完成

コレで完成!Web フォントは容量がまだまだ気になるものの、狙った書体で確実に表示させられる良いテクだ。