JavaScriptでインストールされているフォントを調べてクラスを付与する

インストールされているフォントを確認する
インストールされているフォントを確認する

以前から調べていて方法が分からなかったのに、たまたま最近調べた際に幾つか情報がみつかったのでまとめたいと思います。

テーマは、PCなどの端末やデバイスに特定のフォントがインストールされているかどうかを調べ、その有無をクラスとして出力する方法です。

残念ながら自作ではなく、他の方が開発された情報のお知らせのような薄い内容です。

構築環境
JavaScriptfontdetect.js
対応ブラウザIE9+

実現したいこと

実現したいことは以下の通り。

  • PCやデバイスにインストールされているフォントを判別
  • 特定のフォントの有無をクラスに反映させる
  • レンダリングされているフォントに対応したcss指定を実現する

メイリオのように極端にディセンダが違うフォントを用いる場合、そのフォントが使えるか使えないかで特にリストマーカーを画像で設定する際の表示位置が狂いやすく、そういった問題への対応策として期待していました。

JavaScriptでフォントを判別する方法

基本的な原理は同じようなのですが、複数の情報があります。

初めに完成版とも言えそうな情報から記載します。

IE8以下は不可とのこと(README.mdに記述あり)ですが、iPhone4とAndroid4.2の実機で確認したところ、どちらでも動作を確認しました。

上記ページから移動できるFontDetectというjsファイルを使えば、htmlタグに指定したフォント名でクラスが設定されます。

以下はMeiryoを指定した場合の例です。

  • Meiryo(Meiryoがインストールされている場合)
  • no-Meiryo(Meiryoがインストールされていない場合)

指定方法の凡例は以下の通りです。


<script>
// Basic
FontDetect.test('gillsans', 'Gill Sans');

// Slug can be omitted (Assumed as 'segoeui')
FontDetect.test('Segoe UI');

// Multiple family names as an array
FontDetect.test('palatino', [ 'Palatino', 'Palatino Linotype' ]);

// Multiple tests as an object
FontDetect.test({
    meiryo: 'Meiryo',
    mincho: [ 'Hiragino Mincho ProN', 'Yu Mincho', 'YuMincho' ]
});
</script>

複数のフォント指定は Multiple tests as an object の項目の記述方法になるようです(またはFontDetect.test()関数を複数書くか)。

判別する仕組みに関して

仕組みといいますか動作の概要ですが、以下に引用します。

  1. 幅が 0 の A だけのフォントを作り、Data URI で CSS に埋め込む
  2. A のテキストをダミーとして HTML に挿入し、1 のフォントを指定する
  3. 目的のフォントファミリを指定し、幅が 0 より大きくなれば true

上記を読んでも最初はよくわからなかったのですが、最終的な自分なりの理解は以下のとおりです。

  1. JavaScriptにて、横幅が0のフォントを埋め込む
  2. JavaScriptにて、spanで「A」を一文字だけhiddenでHTMLに挿入する
  3. 挿入した「A」に対し、横幅0のフォントを適用する
  4. 横幅0のフォントを適用した「A」に、確認したいフォント名でfont-familyを指定する
  5. 確認したいフォントがインストールされていれば適用され、横幅0のフォントではなくなり、「A」の横幅が0より大きくなる
  6. 確認したいフォントがインストールされていなければ、横幅0のフォントのままであり、「A」の横幅も0のままとなる
  7. 最終的な「A」の幅を検出し、0かどうかを調べ、確認したいフォントがあるかどうかの判別とする

ちなみに、FontDetectの元となったのは以下のページの情報だそうです。

こちらでは「A」ではなく「あ」を使っている模様です。

JavaScriptでフォントを判別するその他の方法

フォントの幅に着目している点は同じですが、以下のページでは詳細が少し違う判別法を用いています。

2007年に公開された情報で、最新版は2012年です。

こちらの仕組みは概ね以下の内容かと思います。

  1. フォントごとに文字の横幅が違う
  2. このライブラリでは、デフォルトのフォントしてmonospacesans-serifserifの3つを指定する
  3. 72pxで「mmmmmmmmmmlli」という文字列を挿入する
  4. 挿入した文字列に対して確認したいフォント名を適用する
  5. 文字列の横幅が変化するかどうかで、確認したいフォントがインストールされているかを判別する

なお、文字列と72pxの意図は以下のようなもののようです(詳細はコード内にコメントで説明されています)。

  • 「m(又はwでも可)」はフォントの中でも横幅が最も大きいと考えられるため、フォントが変わった際の幅の差を検知しやすい
  • フォントサイズが大きい方が誤差が分かりやすいため、制作者が大きいと判断した72pxを用いている

横幅0のフォントではなく、デフォルトとしてserifなどのフォントを適用し基準としている点が違います。

読み込ませるデータ量は減るので多少軽量になると思いますが、monospaceはともかくsans-serifserifは特定のフォント名でないため、以下のような問題が発生するのではと思います。

  • sans-serifserifは特定のフォント名ではなく、それぞれデフォルトで設定されているゴシック体系と明朝体系のフォントが適用される
  • sans-serifserifで適用されるフォントと確認したいフォント名が同じ場合、文字列の横幅が変わらずフォントの有無が確認ができない

クライアント側の環境は様々であるため、横幅0のフォントを埋め込む方が確度の高い確認方法かもしれません。

類似の仕組み

前項と同種ですが、以下の記事も参考になるかと思います。

上記は2010年公開ですが、2007年公開の前項の記事との関連は明記されていないので判断はできませんでした。

結び

JavaScriptによるフォントの判別は非常に難しいと思っていたのですが、原理的には2007年にできており、使いやすい形のjsファイルとして2014年には形になっていました。

以前調べてもまったくわからなかったのが不思議ですが、探し方が悪かったのか、目にしていても理解できていなかったのかなと思います。

ちなみに、今回の仕組みはIE8以下には使えないため、結局本番への実装は諦めています。

12人がこの記事を評価

役に立ったよという方は上の「記事を評価する」ボタンをクリックしてもらえると嬉しいです。

連投防止のためにCookie使用。SNSへの投稿など他サービスとの連動は一切ありません。

コメント欄