【2022年3月】Google Fontsのパフォーマンス比較&ハリー・ロバーツ方式の勝手に改良版 にて、Google Fontsを遅延読み込みする方法についてまとめました。
しかし、この方法では「 FOUT(Flash of Unstyled Text)」という現象が避けられません。
- ページの読み込み開始:OS・ブラウザのデフォルトフォント
- フォントの読み込み完了:Webフォント
という順番でページが表示されるため、デフォルトフォント→Webフォントにパチッと切り替わる際に文字が動く現象です。
本当はできるといいこと
本当はできるとよいことは、可変フォントを利用するなどして読み込み前・読み込み後の文字の大きさや位置のズレをできる限り少なくすることです。
ただ、今回は文字のbaselineのズレ(たぶん)をうまく吸収できなかったのでもう少しお手軽な方法です。
今回はフォントの読み込み開始まで文字を消して、フェードインさせる
フォントの読み込み完了まで文字を消しておくのはあまり良い方法ではありませんが、どうしてもFOUTを発生させたくない場合には選択肢になります。
フォントの読み込みができているかどうかを検知して、読み込み完了後に文字をフェードインする方法
今回は Zen Kaku Gothic Newを使っていますので、適宜HTML・JS・CSSの Zen Kaku Gothic New の部分はbodyで使うWebフォント名に置き換えてください。
<body class="no-js">
<!-- ページ最下部に、フォントの読み込み検知用の要素を設置 -->
<div aria-visibility="hidden" class="hidden" style="font-family: 'Zen Kaku Gothic New'">
    あ
</div>
<script src="loading.js"></script>
</body>document.getElementsByTagName("body")[0].classList.remove("no-js");
var interval = null;
function fontLoadListener() {
    var hasLoaded = false;
    try {
        hasLoaded = document.fonts.check('12px "Zen Kaku Gothic New"')
    } catch (error) {
        console.info("CSS font loading API error", error);
        fontLoadedSuccess();
        return;
    }
    if (hasLoaded) {
        fontLoadedSuccess();
    }
}
function fontLoadedSuccess() {
    if (interval) {
        clearInterval(interval);
    }
    document.getElementsByTagName("body")[0].classList.add("wf--loaded");
}
interval = setInterval(fontLoadListener, 500);body:not(.wf--loaded):not(.no-js) {
    /* フォント読み込み前 */
    font-size: 16px;
    font-family:  YuGothic, "Yu Gothic Medium", "Yu Gothic", sans-serif;
    letter-spacing: .05em;
    line-height: 2;
    color: transparent;
}
.wf--loaded,
.no-js {
    /* フォント適用後 */
    font-size: 16px;
    font-family: "Zen Kaku Gothic New", sans-serif;
    letter-spacing: .05em;
    line-height: 2;
    color: #010101;
    transition:color 0.2s;
}
/* フォント読み込み検知用の要素を、検知可能なまま見えなくする */
.hidden {
    position: absolute;
    overflow: hidden;
    clip: rect(0 0 0 0);
    height: 1px;
    width: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
}初回アクセス時以外はすぐさま文字を表示したい
文字をフェードインさせることはできましたが、ページ遷移するたびに文字が消えるのはちょっと目にうるさいですね。
webフォントの読み込みがされたことをクッキーに保存するバージョンに変更してみます。
document.getElementsByTagName("body")[0].classList.remove("no-js");
//cookieにwfがあったら、.wf--loadedをつける。
var cookies = document.cookie; 
var cookiesArray = cookies.split(';');
for(var c of cookiesArray){
    var cArray = c.split('=');
    if( cArray[0] == 'wf'){ 
        document.getElementsByTagName("body")[0].classList.add("wf--loaded");
    }
}
var interval = null;
function fontLoadListener() {
    var hasLoaded = false;
    try {
        hasLoaded = document.fonts.check('12px "Zen Kaku Gothic New"')
    } catch (error) {
        console.info("CSS font loading API error", error);
        fontLoadedSuccess();
        return;
    }
    if (hasLoaded) {
        //cookieにwfを保存。
        document.cookie = "wf=loaded"
        fontLoadedSuccess();
    }
}
function fontLoadedSuccess() {
    if (interval) {
        clearInterval(interval);
    }
    document.getElementsByTagName("body")[0].classList.add("wf--loaded");
}
interval = setInterval(fontLoadListener, 500);これでページ遷移するたびに毎回文字をフェードインさせることなく、快適に表示できるようになりました。
※この方法だとハード再読み込み(webフォントのキャッシュを消す)をすると、FOUTが発生します。
読み込みが遅い環境だと問題が起きる?→問題ありません。
「フォントの読み込みが終わるまで文字を消す」という方法をとると、低速回線では文字が表示されない時間がとても長くなるのではないか?と考えますよね。
しかしなんと、心配ありません。低速な環境の場合はFOUTを発生させつつ文字が表示されるため、文字が消えっぱなしになるということはありません。
この記事を参考にしました

コメント