TypeKitとかがやってるWebフォントの読み込みが終わったらhtml
要素にクラス名を振るアレの話。TypeKitがオープンソースでリリースしているWebFont Loaderを使う方法が安全で安定。Googleがホスティングしているのもあるので手軽でもある。でも読み込み完了の検知以外にも機能があってパワフルすぎる気がするので、Adobe Blankを使って自前で書いてみることにした。
Adobe Blankはそのまま使うと30KB以上ある。読み込み完了検知だけなら幅0のグリフが1つあればそれで良いので、まずはサブセット化してサイズを抑えることから。a
だけのWOFFなAdobe Blankを作ればちょうど1KBくらいになる。
Download: adobe-blank.woff
@font-face
定義の追加外部リクエストにすると意味が薄れるのでDataURIを使って既存のCSSに混ぜ込む。
@font-face {
font-family: 'Adobe Blank';
src: url('data:application/font-woff;base64,d09GRgAB...') format('woff');
}
これをfont-family
に指定した要素では、a
しかテキストのない場合に幅が0
になる。なので以下の様な要素を作っておくとWebフォント(Source Sans Proを例にする)の読み込みが完了すると幅が増えることになる。つまりこの要素の幅を監視すれば読み込み完了の検知が出来る。
<div style="font-family:'Source Sans Pro', 'Adobe Blank';
position: absolute;
top: -100px;">
a
</div>
要素の生成から監視までを全てJavaScriptでやると良い。タイマー使わない方法も模索したい所だけどまずは普通のアプローチで。
function detectFontLoading(fontName) {
var tester = document.createElement('span');
tester.style.fontFamily = '"' + fontName + '", "Adobe Blank"';
tester.style.position = 'absolute';
tester.style.top = '-100px';
tester.appendChild(document.createTextNode('a'));
document.body.appendChild(tester);
var timerId = setInterval(checkWidth, 500);
function checkWidth() {
if (tester.offsetWidth > 0) {
clearInterval(timerId);
document.documentElement.className += ' ' + fontName.toLowerCase().replace(/\s/g, '_');
tester.parentNode.removeChild(tester);
}
}
}
detectFontLoading("Source Sans Pro");
これでSource Sans Proの読み込みが完了すると、html
要素にsource_sans_pro
というクラス名が振られる。どのブラウザーでも読み込みの完了前から文字は表示され読めるという前提の話になっているので、特に急がずに500ミリ秒間隔とかでチェックすれば良さそう。もっとゆっくりでも良いかも。ずっとチェックし続けるのでタイムアウトは設定できるようにするべきだけどやってない。
あとはCSSをこれに見合った形で書いてやるだけ。
body {
font-family: "Helvetica Neue", "Calibri", sans-serif;
}
.source_sans_pro body {
font-family: "Source Sans Pro", sans-serif;
}
Source Sans Proの読み込みが完了するまではHelvetica NeueまたはCalibriでとりあえず表示され、読み込みが完了するとSource Sans Pronに置き換わる。
Webフォントの読み込み完了の検知はつまるところFOUT対策なわけだけど、今後どうなるんだろう。Firefoxの挙動が一番素直でマシだと感じているので、それに揃うといいなぁと思っている。