Perfect YouTube Core Web Vitals
Learn how to embed YouTube videos without losing PageSpeed
結論:headにdeferを指定します
最終レビュー:2026年3月、Arjen Karel
かつての標準的なアドバイスは、JavaScriptをフッターに配置することでした。このアドバイスはすでに時代遅れです。すべてのブラウザがasyncとdeferをサポートしている現在、ほとんどのスクリプトにとって最適な配置場所は、defer属性を付与して<head>に記述することです。
その理由は、preload scannerにあります。ブラウザはhead内のスクリプトを即座に検出し、HTMLのパースと並行してダウンロードを開始します。フッターのスクリプトは検出が遅れるため、ダウンロードの開始も遅くなります。結果として、レンダリングをブロックしない挙動は同じですが、リソース of 検出が早くなります。
2025 Web Almanacによると、未だに85%のページがrender blockingリソースの監査で不合格となっています。これは極めて大きな数値です。一方、モバイルのTotal Blocking Timeは前年比で58%増加し、中央値は1,916ミリ秒に達しています。JavaScriptは軽量化するどころか、年々肥大化しています。スクリプトの配置を正しく設定することは、First Contentful PaintとLargest Contentful Paintを改善するための最も簡単な方法の1つです。
preload scannerの仕組み
preload scannerは、メインパーサーに先んじて動作する第2のHTMLパーサーです。生のHTMLをすばやくスキャンし、メインパーサーが到達する前に重要なリソース(画像、CSS、JavaScript)の取得を開始します。preload scannerは、基本的にはリソースを検出した順番で取得します。
ここに、スクリプトの配置場所が重要になる理由があります。<head>内にあるスクリプトは、ほぼ即座に検出されます。</body>の直前に配置されたスクリプトは、特にHTMLドキュメントのサイズが大きい場合に検出が遅れます。モバイル接続では、その遅延によって数百ミリ秒の損失が生じます。
JavaScriptによって動的に注入されるスクリプトは、preload scannerからは完全に検知されません。preload scannerは、サーバーから返されるHTMLマークアップ内に存在するリソースのみを検出します。そのため、コードを使ってスクリプトを注入するよりも、HTML属性を使用してJavaScriptをdefer指定する方がほぼ常に優れています。
headにJavaScriptを配置する場合
JavaScriptをページの<head>に配置すると、preload scannerによって最も早いタイミングで検出されます。
メリット
- 早期検出:preload scannerは、body内のコンテンツよりも先にhead内のスクリプトを見つけます。ダウンロードは可能な限り早い段階で開始されます。
- 早期実行:head内のスクリプト(
defer付き)は、ドキュメントの後半で検出されるスクリプトよりも先に実行されます。詳細な比較については、JavaScriptのdefer対async、およびCore Web Vitalsを参照してください。 - コードの分離:スクリプトの参照を
<head>にまとめることで、コンテンツのマークアップと分離され、HTMLのメンテナンスが容易になります。
デメリット
- render blocking(deferまたはasyncなしの場合):head内の通常の
<script>は、スクリプトのダウンロードと実行が完了するまでHTMLのパースをブロックします。これはFirst Contentful Paintに致命的な悪影響を与えます。これを防ぐため、head内の外部スクリプトには必ずdeferまたはasyncを使用してください。 - 帯域幅の競合:優先度の高いheadスクリプトは、CSS、フォント、およびLCP画像と帯域幅を奪い合います。低速な回線では、これによりLargest Contentful Paintがしきい値である2.5秒を超えてしまう原因になります。
head配置を使用すべき状況
メニュー、Cookie同意バナー、スライダーなど、訪問者がファーストビューで目にする領域に影響を与える、ページ体験に不可欠なスクリプトには<head>を使用します。render blockingを防ぐために、defer(実行順序が問われない場合はasync)を付与してください。機能検知ライブラリも、bodyのパース前に実行する必要があるため、headに配置する必要があります。
フッターにJavaScriptを配置する場合
閉じタグ</body>の直前にJavaScriptを配置することは、長年にわたりパフォーマンス改善の標準的なアドバイスでした。その考え方は、HTMLのレンダリングを優先し、スクリプトのダウンロードは後回しにするというものです。
メリット
- デフォルトで非ブロッキング:フッターのスクリプトより上にあるHTMLはすでにパースされているため、初期レンダリングをブロックしません。
- 帯域幅競合の低減:ブラウザがフッターのスクリプトに達する頃には、CSS、フォント、およびLCP画像のダウンロードはすでに開始されています。
デメリット
- 検出の遅れ:preload scannerがフッターのスクリプトを検出するタイミングは、headのスクリプトより遅くなります。大規模なページでは、ダウンロードの開始と実行がそれだけ遅れることになります。
- 古いパターン:
<head>内で<script defer>を使用すれば、より早いタイミングで検出され、非ブロッキングの挙動を同様に実現できます。フッターへの配置は、deferがすべてのブラウザで汎用的にサポートされる前の一時的な回避策でした。その時代はすでに終わっています。
フッター配置が依然として有効な状況
初期読み込み時に帯域幅を競合させたくないスクリプト(アナリティクス、A/Bテストツール、SNSウィジェットなど)については、フッター配置が有効な場合があります。しかし、これらのスクリプトであっても、preload scannerによる早期検出の恩恵を受けるため、通常はheadにdeferを指定して配置する方が優れた選択肢となります。
モダンなスクリプト属性
asyncとdeferの他に、知っておくべき属性が2つあります。
type="module":モジュールスクリプトは、デフォルトでdefer動作となります。すでに遅延実行されるようになっているため、deferを追加する必要はありません。モジュールスクリプトにasyncを追加すると、デフォルトのdefer挙動が上書きされ、ダウンロード完了後すぐに実行されます。
fetchpriority:デフォルトでは、asyncおよびdeferスクリプトのネットワーク優先度はLowに設定されます。asyncスクリプトにfetchpriority="high"を追加すると、レンダリングをブロックせずにHigh優先度でダウンロードできます。これは、ユーザー体験にとって不可欠でありながら、レンダリングをブロックすべきではないスクリプトにとって理想的な組み合わせです。詳細については、リソース優先度設定ガイドおよびJavaScriptの優先度レベルを参照してください。
実践的なスクリプト配置戦略
すべてのスクリプトを同じように扱うべきではありません。私は4つの層に分けるアプローチをとっています。
- 描画に不可欠なスクリプト:ページの表示レイアウトに影響を与えるスクリプト(メニュー、スライダー、ファーストビューのUIなど)。ファーストペイントの前に実行する必要がある場合は、
deferなしで<head>に配置します。これらのスクリプトはレンダリングをブロックし、Core Web Vitalsを悪化させるため、可能な限りサイズを小さく抑えてください。 - 重要なスクリプト:コンバージョンやインタラクションに欠かせないスクリプト(フォーム、ナビゲーション、Cookie同意など)。
<head>内にdeferまたはasyncを付与して配置します。 - 通常のスクリプト:ページの初期描画に影響しないスクリプト(カルーセル、モーダル、タブなど)。
<head>内にdeferを付与して配置します。 - 必須ではないスクリプト:最悪の場合は機能がなくても困らないスクリプト(アナリティクス、チャットウィジェット、SNSシェアボタンなど)。
loadイベントやrequestIdleCallbackを使用して、ページのレンダリング完了後に読み込みます。具体的な手法についてはJavaScriptを遅延させる16の方法を参照してください。このカテゴリの未使用のJavaScriptが多い場合は、未使用のJavaScriptを削減する方法を参照してください。
DOMContentLoadedイベントおよびloadイベントを使用すると、HTML内でのスクリプトの記述位置に関係なく、実行のタイミングを制御できます。コードを適切なタイミングで確実に実行させるために有用です。
コード例
例1:head内のJavaScript(render-blocking)
<!DOCTYPE html>
<html>
<head>
<title>JavaScript in the Head Example</title>
<script>
function showMessage() {
alert("Hello from JavaScript in the head!");
}
</script>
<!-- このスクリプトはレンダリングをブロックします -->
<script src="script.js"></script>
</head>
<body>
<button onclick="showMessage()">Click Me</button>
</body>
</html>
この例では、<head>内のscript.jsがレンダリングをブロックします。ブラウザはスクリプトのダウンロードと実行が完了するまでボタンを表示しません。これを解消するには、scriptタグにdeferを追加してください。
例2:フッター内のJavaScript
<!DOCTYPE html>
<html>
<head>
<title>JavaScript in the Footer Example</title>
</head>
<body>
<button onclick="showMessage()">Click Me</button>
<!-- bodyの末尾のスクリプト -->
<script src="script.js"></script>
<script>
function showMessage() {
alert("Hello from JavaScript in the footer!");
}
</script>
</body>
</html>
ここでは、script.jsがHTMLコンテンツの後に読み込まれるため、レンダリングはブロックされません。しかし、preload scannerによる検出はheadに配置した場合よりも遅くなります。<head>内で<script defer src="script.js"></script>を使用すれば、早い段階でダウンロードが検出され、同様の非ブロッキング動作を実現できます。
例3:イベントリスナーの使用
<!DOCTYPE html>
<html>
<head>
<title>Event Listener Example</title>
<script>
window.addEventListener('load', function() {
console.log("Page is fully loaded.");
});
</script>
</head>
<body>
<!-- ページコンテンツ -->
</body>
</html>
loadイベントリスナーを使用すると、スクリプトの記述位置に関係なく、コールバック内のコードはページが完全にロードされた後にのみ実行されます。他のすべての準備が整うまで待機すべき、優先度の低い初期化処理を行う場合に適しています。
変更の検証
スクリプトをフッターから<head>内のdeferへ移動した後は、Real User Monitoringでその効果を検証してください。FCPとLCPの双方が改善します。CoreDashで監視されているサイト全体において、スクリプトの大部分にdeferを使用しているオリジンは、依然としてフッター配置に依存しているオリジンと比較して、FCPの中央値が18%高速です。