レンダリングに使われているフォントと、ブラウザで使えるフォントを取得する

「あのdiv要素は、どのフォントでレンダリングされているの?」「どのフォントがブラウザ上で利用可能なの?」といった基本的な情報が、CSSCSS API からは(残念ながら)取得できません。

/* 実際に使われるフォントは一体どれなの? */

font: 24pt 'メイリオ', Meiryo, 'ヒラギノ角ゴ Pro W3', 'Hiragino Kaku Gothic Pro', 'MS Pゴシック', sans-serif;

ライトなユーザには不必要な情報でも、高度なWebアプリを組もうとすると、そういったレアな情報が欲しくなったりします。

仕方が無いので、いつものようにゴニョゴニョするのです。

レンダリングで使われているフォントを取得する

やり方としては…

  • window.getComputedStyle(node, null).fontFamily を取得
    • IE なら node.currentStyle.fontFamily
  • fontFamily の値をカンマで切断し、余計な空白を除去
  • <div style="font: 72pt フォント">適当な文字列</div>を用意し、幅/高さを測定
    • 72ptである必要はありませんが、できるだけ大きな値を指定します。
  • 幅/高さが一致するフォントが、現在レンダリングで使われているフォント

で取れます。

uu.font.js

// uu.font.detect
function fontdetect(node) { // @param Node:
                            // @return String: detected font, eg: "serif"
    var fam = window.getComputedStyle(node, null).fontFamily,
        ary = uu.split.token(fam, ","), i = -1, // カンマ区切りで切断
        a, b = fontmetric("72pt " + fam); // コンテントボックスのサイズを取得

    while ( (v = ary[++i]) ) {
        a = fontmetric("72pt " + v);
        if (a.w === b.w && a.h === b.h) { // サイズが一致
            return v; // match
        }
    }
    return "";
}

DEMO
# Opera だと面白くない結果に

このフォントは使えるの? を判別する

やり方としては…

  • まず、ありえないフォントを指定して、幅/高さを測定
  • 次に、検査したいフォントを指定して、幅/高さを測定
  • 利用可能なフォントなら幅/高さが変化するので、調べたいフォントを順番に試す

な感じです。

uu.font.js

// uu.font.able
function fontable(fontName) { // @param String: font name, "Arial"
                              // @return Boolean: true is installed
    var a = fontmetric("72pt dummy"),
        b = fontmetric("72pt " + fontName);

    return a.w !== b.w || a.h !== b.h;
}

var _metricNode,   // [lazy] Measure Text Metric Node
    _BASE_STYLE = "position:absolute;border:0 none;margin:0;padding:0;";

// uu.font.metric - measure text rect(width, height)
function fontmetric(font,   // @param CSSFronString: "12pt Arial"
                    text) { // @param String(= "aABCDEFGHIJKLMm"):
                            // @return Hash: { w, h }
    if (!_metricNode) {
        _metricNode = doc.createElement("div");
        _metricNode.style.cssText = _BASE_STYLE +
            "top:-10000px;left:-10000px;text-align:left;visibility:hidden";
        doc.body.appendChild(_metricNode);
    }
    _metricNode.style.font = font;
    _metricNode[uu.gecko ? "textContent"
                         : "innerText"] = text || "aABCDEFGHIJKLMm";
    return { w: _metricNode.offsetWidth,
             h: _metricNode.offsetHeight };
}

です。そんなに難しくありませんね。

DEMO
# Firefox, IE, Chrome に比べ OperaSafari では使えるフォントに制限があるようです

デモは Windows で見てください。