この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:4
ページ更新者:guest
更新日時:2026-06-11 07:29:05

タイトル: scriptタグの記載場所
SEOタイトル: HTML script タグ配置完全ガイド (defer/async)

この記事の要点
  • <script> の配置は 内 + defer 属性が現代のベストプラクティス
  • 昔は の閉じタグ直前に置くテクニックが主流だった (HTML パースをブロックしないため)
  • defer: HTML パース完了後に実行、複数 script の順序保持
  • async: ダウンロード完了次第すぐ実行、順序保証なし、依存関係のない計測タグ向き
  • type="module" は自動で defer 扱い。最新の ES Modules はこれで OK

結論: 現代のベストプラクティス

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>例</title>

  <!-- ✅ 自前 JS: head 内に defer で -->
  <script src="/js/main.js" defer></script>

  <!-- ✅ ES Modules は自動で defer -->
  <script src="/js/app.mjs" type="module"></script>

  <!-- ✅ サードパーティ計測 (依存関係なし): async -->
  <script src="https://www.googletagmanager.com/gtag/js?id=G-XXX" async></script>
</head>
<body>
  <h1>コンテンツ</h1>
</body>
</html>

script タグの 3 つの読み込みモード

モードHTML パース実行タイミング順序保証
<script> (素)ブロックダウンロード完了次第即実行
<script defer>ブロックしないHTML パース完了後、DOMContentLoaded 前
<script async>ブロックしないダウンロード完了次第即実行×
<script type="module">ブロックしないdefer と同等

歴史: なぜ 末尾に置くテクニックが流行ったか

2000 年代後半〜 2010 年代前半、まだ defer/async が普及していなかった頃、<script><head> に置くと:

  1. ブラウザは HTML パース中に script タグに遭遇
  2. JS ファイルのダウンロード・実行が完了するまでHTML パースを停止
  3. 結果、ユーザーには白画面が長く表示される

これを避けるため、「</body> の直前に置けば HTML パースは終わってる」というテクニックが広まりました。jQuery 全盛期の Web 制作本はほぼこのスタイルです。

<!-- 旧来のスタイル (jQuery 時代) -->
<!DOCTYPE html>
<html>
<head>
  <title>例</title>
</head>
<body>
  <h1>コンテンツ</h1>

  <!-- ページ最後に置くことでパースブロックを回避 -->
  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
  <script src="/js/main.js"></script>
</body>
</html>

defer 属性 (推奨)

defer を付けると、ブラウザは:

  1. script を並行ダウンロード (HTML パースをブロックしない)
  2. HTML パース完了後に、記述順に実行
  3. DOMContentLoaded イベントの直前に実行される
<head>
  <!-- 順序が保持される -->
  <script src="/js/jquery.js" defer></script>     <!-- 1番目に実行 -->
  <script src="/js/plugin.js" defer></script>     <!-- 2番目に実行 -->
  <script src="/js/main.js" defer"></script>      <!-- 3番目に実行 -->
</head>

async 属性

async も並行ダウンロードしますが、ダウンロードが完了した順に即実行します。順序は保証されません。

<head>
  <!-- 順序不定 (依存関係があるとバグる) -->
  <script src="/js/jquery.js" async></script>
  <script src="/js/plugin.js" async></script>  <!-- jquery より先に走ることがある -->
</head>

<!-- ✅ 単独で動く計測タグや広告タグには async が最適 -->
<script src="https://www.googletagmanager.com/gtag/js?id=G-XXX" async></script>
<script src="https://connect.facebook.net/en_US/sdk.js" async></script>

type="module" (ES Modules)

ES Modules (import/export を使うモジュール) は常に defer 扱いです。明示的に defer を書かなくても OK:

<script type="module" src="/js/app.mjs"></script>
<!-- defer 相当 + strict mode + import/export 使える -->

<!-- インラインモジュール -->
<script type="module">
  import { greet } from '/js/lib.mjs';
  greet('world');
</script>

<!-- 古いブラウザ用のフォールバック -->
<script nomodule src="/js/legacy-bundle.js"></script>

Critical CSS との関係 (Web Vitals)

Core Web Vitals の LCP (Largest Contentful Paint) 改善には、ファーストビュー描画を阻害しないことが重要です。defer / async の徹底に加え、Critical CSS のインライン化を組み合わせます:

<head>
  <!-- 1. Critical CSS をインライン (ファーストビュー描画用) -->
  <style>
    /* hero / nav の最低限のスタイル */
    body { margin: 0; font-family: sans-serif; }
    .hero { height: 60vh; background: #4a90e2; }
  </style>

  <!-- 2. 残りの CSS は非同期に -->
  <link rel="preload" href="/css/main.css" as="style"
        onload="this.onload=null;this.rel='stylesheet'">
  <noscript><link rel="stylesheet" href="/css/main.css"></noscript>

  <!-- 3. JS は defer -->
  <script src="/js/app.js" defer></script>

  <!-- 4. 計測タグは async -->
  <script src="/gtag.js" async></script>
</head>

Resource Hints (preload/prefetch/preconnect)

ヒントを使うとさらに高速化できます:

<head>
  <!-- 重要 JS を早期ダウンロード開始 -->
  <link rel="preload" href="/js/critical.js" as="script">

  <!-- 次ページで使うリソースを先読み -->
  <link rel="prefetch" href="/js/next-page.js">

  <!-- 接続だけ先に確立 -->
  <link rel="preconnect" href="https://api.example.com">
  <link rel="dns-prefetch" href="https://cdn.example.com">

  <script src="/js/critical.js" defer></script>
</head>

サードパーティ JS の遅延読込

チャットウィジェット・コメント欄・SNS シェアボタン等、ファーストビューに不要な JS は意図的に遅延させると Web Vitals が上がります:

// ユーザー操作後にチャットウィジェットを読み込む
document.addEventListener('scroll', loadChat, { once: true });
document.addEventListener('click', loadChat, { once: true });

function loadChat() {
  const s = document.createElement('script');
  s.src = 'https://widget.example.com/chat.js';
  s.async = true;
  document.head.appendChild(s);
}

// または IntersectionObserver で要素が見えたとき
const obs = new IntersectionObserver((entries) => {
  if (entries[0].isIntersecting) {
    const s = document.createElement('script');
    s.src = '/js/comments.js';
    document.head.appendChild(s);
    obs.disconnect();
  }
});
obs.observe(document.querySelector('#comments-section'));

使い分け早見表

JS の種類推奨配置属性
自前のアプリケーション JShead 内defer
ES Moduleshead 内type="module"
GA / GTM / Facebook Pixelhead 内async
jQuery + プラグインhead 内defer (順序保持)
インライン script (極小)head 内 or body 内属性不要
レガシーブラウザ対応 (IE11)body 末尾属性なし

FAQ

Q: defer と async どちらが速い?
A: ダウンロード速度は同じ。実行タイミングが違うだけです。順序が必要なら defer、不要なら async。

Q: インライン に defer は効く?
A: 効きません。defer/async は外部ファイル (src 指定) にのみ有効です。

Q: body 末尾でも defer は必要?
A: body 末尾なら不要ですが、現代では head + defer に統一すると保守しやすいです。