Produced by Fourier

JavaScriptの読み込み時にblocking=”render”でFOUC対策

Sena Sena カレンダーアイコン 2023.11.10

⚠️ この機能は今後変わる可能性があり、2023/11/09現在の状況で実験して書いた物です。

はじめに

以前、JavaScript呼び出し時のasyncにていての記事を書きました。

JavaScriptの呼び出し時にasyncを付けない方がよいときってどんなとき? thumbnail

JavaScriptの呼び出し時にasyncを付けない方がよいときってどんなとき?

Web Componentsが呼び出される際に、Layout Shiftと判定される可能性があることに気づいたので解説します。

https://www.fourier.jp/techblog/articles/call-webcomponents-with-perser-blocking/

要約すると、JavaScriptのコードの内容によっては、deferやasyncで読み込むとFOUC(ちらつき)が発生してしまうことがあるという内容になります。

Flash of unstyled content - Wikipedia thumbnail

Flash of unstyled content - Wikipedia

https://en.wikipedia.org/wiki/Flash_of_unstyled_content

特に React や Vue.js を使ったサイトでは、ローディング画面を作って  FOUC  を防止することが多いと思いますが、閲覧者にとっては(ブラウザの)ローディングした後にローディングとなってしまいます。

なんとかする方法は無いかと Chrome の開発ブログを見ていましたが、ついに出ました!

https://chromestatus.com/feature/5452774595624960

FOUCへの救世主 blocking=”render”

Feature proposal: `blocking="render"` attribute on <link>, <script> and <style> · Issue #7131 · whatwg/html thumbnail

Feature proposal: `blocking="render"` attribute on <link>, <script> and <style> · Issue #7131 · whatwg/html

(Edit: The syntax is changed into blocking="render" for extensibility. ) (Please refer to the full proposal for formal details and more discussion) Explainer All current browsers already have a ren...

https://github.com/whatwg/html/issues/7131

<script async blocking="render" src="async-script.js"></script>

blocking=”render” を付けることにより、レンダリングの開始前に評価されます。

今まではレンダリングされた後に評価・実行されてしまっていたのでFOUCが発生していましたが、これで防ぐことが出来ます!

軽く実験

以下のようなJavaScriptを書いたとします。

'use strict';
{
    const root = document.getElementById('root');
    const div = document.createElement('div');
    div.style.paddingBlock = '1000px';
    root.appendChild(div);
}

同じコードをheadタグ内から様々な方法で読み込んでみます。

  1. 同期的に読み込みます。
    <script src="/js/app.js"></script>
  2. deferで読み込みます。
    <script defer src="/js/app.js"></script>
  3. asyncで読み込みます。
    <script async src="/js/app.js"></script>
  4. 2.にblocking=”render”を付けて読み込みます。
    <script defer blocking="render" src="/js/app.js"></script>

Performance InsightsでCumulative Layout Shift (CLS)の値を図ってみると、以下のような結果になりました。

レンダリング方法 Cumulative Layout Shift (CLS)
同期的に読み込む 0.436
deferで読み込む 0.436
asyncで読み込む 0.436
blocking=”render”を付けて読み込む 0

濫用に注意

blocking=”render” を使えばレンダリングブロックを意図的に行える事が分かりました。

ただし、レンダリングが遅くなるため、UXやSEO的には弱くなります。

レンダリング ブロック リソースを回避する  |  Publisher Ads Audits for Lighthouse  |  Google for Developers thumbnail

レンダリング ブロック リソースを回避する  |  Publisher Ads Audits for Lighthouse  |  Google for Developers

https://developers.google.com/publisher-ads-audits/reference/audits/ad-render-blocking-resources?hl=ja

そのため blocking=”render” が必要なリソースかどうか見極める必要があります。

まとめ

blocking=”render” が使えるようになれば、簡単にFOUCを防ぐ事が出来ます。

執筆時では対応しているブラウザが少ないですが、非常に便利な機能なので対応ブラウザが増えて欲しいところです。

https://caniuse.com/mdn-api_performanceresourcetiming_renderblockingstatus

Sena

Sena slash forward icon Engineer

生涯に亘り技術を極めていきたい。

関連記事