Corredor

ウェブ、プログラミングの勉強メモ。

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

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

neos21.hatenablog.com

neos21.hatenablog.com
↑コッチで紹介しているやり方の方が良い。

一方、このサイトは技術ブログであり、コードを掲載する機会も多いので、等幅フォントについても気を使う。コード内のコメントには日本語を使うので、日本語文字を有する等幅フォントで、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 をダウンロードする。

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

  • NotoSansMonoCJKjp-Regular.otf
  • NotoSansMonoCJKjp-Bold.otf

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

WOFF 形式に変換する

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

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

  • NotoSansMonoCJKjp-Regular.woff2
  • NotoSansMonoCJKjp-Regular.woff
  • NotoSansMonoCJKjp-Bold.woff2
  • NotoSansMonoCJKjp-Bold.woff

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 フォントで表示できていることだろう。

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

  • Windows では local("NotoSansMonoCJKjp-Regular")local("Noto Sans Mono CJK JP Regular")local("NotoSansMonoCJKjp-Bold")local("Noto Sans Mono CJK JP Bold") の4つの指定の仕方では効かなかった。local("Noto Sans Mono CJK JP") は有効になったが、font-weight を指定しても Bold が有効にならなかった
  • Mac では FontBook.app における「PostScript 名」である local("NotoSansMonoCJKjp-Regular")local("NotoSansMonoCJKjp-Bold") 表記が有効になり、「正式名称」である local("Noto Sans Mono CJK JP Regular")local("Noto Sans Mono CJK JP Bold") 表記は効かなかった。「ファミリー」指定 local("Noto Sans Mono CJK JP") も有効ではあったが、font-weight 指定が正しくできなくなるので使用しない方が良い

よって、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 配布してみることにした。この作業用ディレクトリに近いモノを @neos21/japanese-monospaced-fonts として npm で公開し、unpkg.org という npm パッケージを CDN 配信してくれるサービスを利用してみることにした。

  • @neos21/japanese-monospaced-fonts - npm
    • そういえば、npm publish する時に README.md はアップできているのに npmjs 上に README が反映されずに "Unable to find a readme for @neos21/japanese-monospaced-fonts@1.0.2" というエラーが出てしまうのだけど、コレは何?再 Publish しても治らなかったので諦めてしまった。

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

このように作ったコードとデモを紹介する GitHub Pages を作った。以下よりドウゾ。

unpkg.org CDN を利用して Web フォントを指定するコードは以下のとおり。

@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://unpkg.com/@neos21/japanese-monospaced-fonts@1.0.0/NotoSansMonoCJKjp-Regular.woff2") format("woff2"),
       url("https://unpkg.com/@neos21/japanese-monospaced-fonts@1.0.0/NotoSansMonoCJKjp-Regular.woff")  format("woff"),
       url("https://unpkg.com/@neos21/japanese-monospaced-fonts@1.0.0/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("https://unpkg.com/@neos21/japanese-monospaced-fonts@1.0.0/NotoSansMonoCJKjp-Regular.woff2") format("woff2"),
       url("https://unpkg.com/@neos21/japanese-monospaced-fonts@1.0.0/NotoSansMonoCJKjp-Regular.woff")  format("woff"),
       url("https://unpkg.com/@neos21/japanese-monospaced-fonts@1.0.0/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("https://unpkg.com/@neos21/japanese-monospaced-fonts@1.0.0/NotoSansMonoCJKjp-Regular.woff2") format("woff2"),
       url("https://unpkg.com/@neos21/japanese-monospaced-fonts@1.0.0/NotoSansMonoCJKjp-Regular.woff")  format("woff"),
       url("https://unpkg.com/@neos21/japanese-monospaced-fonts@1.0.0/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("https://unpkg.com/@neos21/japanese-monospaced-fonts@1.0.0/NotoSansMonoCJKjp-Regular.woff2") format("woff2"),
       url("https://unpkg.com/@neos21/japanese-monospaced-fonts@1.0.0/NotoSansMonoCJKjp-Regular.woff")  format("woff"),
       url("https://unpkg.com/@neos21/japanese-monospaced-fonts@1.0.0/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("https://unpkg.com/@neos21/japanese-monospaced-fonts@1.0.0/NotoSansMonoCJKjp-Regular.woff2") format("woff2"),
       url("https://unpkg.com/@neos21/japanese-monospaced-fonts@1.0.0/NotoSansMonoCJKjp-Regular.woff")  format("woff"),
       url("https://unpkg.com/@neos21/japanese-monospaced-fonts@1.0.0/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("https://unpkg.com/@neos21/japanese-monospaced-fonts@1.0.0/NotoSansMonoCJKjp-Regular.woff2") format("woff2"),
       url("https://unpkg.com/@neos21/japanese-monospaced-fonts@1.0.0/NotoSansMonoCJKjp-Regular.woff")  format("woff"),
       url("https://unpkg.com/@neos21/japanese-monospaced-fonts@1.0.0/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("https://unpkg.com/@neos21/japanese-monospaced-fonts@1.0.0/NotoSansMonoCJKjp-Bold.woff2") format("woff2"),
       url("https://unpkg.com/@neos21/japanese-monospaced-fonts@1.0.0/NotoSansMonoCJKjp-Bold.woff")  format("woff"),
       url("https://unpkg.com/@neos21/japanese-monospaced-fonts@1.0.0/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://unpkg.com/@neos21/japanese-monospaced-fonts@1.0.0/NotoSansMonoCJKjp-Bold.woff2") format("woff2"),
       url("https://unpkg.com/@neos21/japanese-monospaced-fonts@1.0.0/NotoSansMonoCJKjp-Bold.woff")  format("woff"),
       url("https://unpkg.com/@neos21/japanese-monospaced-fonts@1.0.0/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://unpkg.com/@neos21/japanese-monospaced-fonts@1.0.0/NotoSansMonoCJKjp-Bold.woff2") format("woff2"),
       url("https://unpkg.com/@neos21/japanese-monospaced-fonts@1.0.0/NotoSansMonoCJKjp-Bold.woff")  format("woff"),
       url("https://unpkg.com/@neos21/japanese-monospaced-fonts@1.0.0/NotoSansMonoCJKjp-Bold.otf")   format("opentype");
}

完成

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

サイトデザインに差をつける Webフォントコレクション (ijデジタルBOOK)

サイトデザインに差をつける Webフォントコレクション (ijデジタルBOOK)

  • 作者: インプレスPC編集部
  • 出版社/メーカー: インプレス
  • 発売日: 2012/03/09
  • メディア: 単行本(ソフトカバー)
  • クリック: 2回
  • この商品を含むブログを見る