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

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

この本文には実行可能なタグ等が含まれるため、安全のためHTMLソースとして表示しています。本文データは変更していません。

<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;background:#fffbea;border:1px solid #f4c430;margin:1em 0;width:100%"><tr><td style="background:#f4c430;color:#000;font-weight:bold;padding:8px">この記事の要点</td></tr><tr><td style="padding:10px"><ul><li><code>&lt;script&gt;</code> の配置は <strong><head> 内 + defer 属性</strong>が現代のベストプラクティス</li><li>昔は <strong><body> の閉じタグ直前</strong>に置くテクニックが主流だった (HTML パースをブロックしないため)</li><li><strong>defer</strong>: HTML パース完了後に実行、複数 script の順序保持</li><li><strong>async</strong>: ダウンロード完了次第すぐ実行、順序保証なし、依存関係のない計測タグ向き</li><li><strong>type="module"</strong> は自動で defer 扱い。最新の ES Modules はこれで OK</li></ul></td></tr></table>
<h2>結論: 現代のベストプラクティス</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;ja&quot;&gt;
&lt;head&gt;
  &lt;meta charset=&quot;UTF-8&quot;&gt;
  &lt;title&gt;例&lt;/title&gt;

  &lt;!-- ✅ 自前 JS: head 内に defer で --&gt;
  &lt;script src=&quot;/js/main.js&quot; defer&gt;&lt;/script&gt;

  &lt;!-- ✅ ES Modules は自動で defer --&gt;
  &lt;script src=&quot;/js/app.mjs&quot; type=&quot;module&quot;&gt;&lt;/script&gt;

  &lt;!-- ✅ サードパーティ計測 (依存関係なし): async --&gt;
  &lt;script src=&quot;https://www.googletagmanager.com/gtag/js?id=G-XXX&quot; async&gt;&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;h1&gt;コンテンツ&lt;/h1&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<h2>script タグの 3 つの読み込みモード</h2>

<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#e3f2fd"><th>モード</th><th>HTML パース</th><th>実行タイミング</th><th>順序保証</th></tr></thead>
<tbody>
<tr><td><code>&lt;script&gt;</code> (素)</td><td><strong>ブロック</strong></td><td>ダウンロード完了次第即実行</td><td>○</td></tr>
<tr><td><code>&lt;script defer&gt;</code></td><td>ブロックしない</td><td>HTML パース完了後、DOMContentLoaded 前</td><td><strong>○</strong></td></tr>
<tr><td><code>&lt;script async&gt;</code></td><td>ブロックしない</td><td>ダウンロード完了次第即実行</td><td>×</td></tr>
<tr><td><code>&lt;script type=&quot;module&quot;&gt;</code></td><td>ブロックしない</td><td>defer と同等</td><td>○</td></tr>
</tbody>
</table>

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

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

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

<p>これを避けるため、「<code>&lt;/body&gt;</code> の直前に置けば HTML パースは終わってる」というテクニックが広まりました。jQuery 全盛期の Web 制作本はほぼこのスタイルです。</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html">&lt;!-- 旧来のスタイル (jQuery 時代) --&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;title&gt;例&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;h1&gt;コンテンツ&lt;/h1&gt;

  &lt;!-- ページ最後に置くことでパースブロックを回避 --&gt;
  &lt;script src=&quot;https://code.jquery.com/jquery-3.6.0.min.js&quot;&gt;&lt;/script&gt;
  &lt;script src=&quot;/js/main.js&quot;&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<h2>defer 属性 (推奨)</h2>

<p><code>defer</code> を付けると、ブラウザは:</p>
<ol>
<li>script を<strong>並行ダウンロード</strong> (HTML パースをブロックしない)</li>
<li>HTML パース完了後に、<strong>記述順に</strong>実行</li>
<li><code>DOMContentLoaded</code> イベントの直前に実行される</li>
</ol>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html">&lt;head&gt;
  &lt;!-- 順序が保持される --&gt;
  &lt;script src=&quot;/js/jquery.js&quot; defer&gt;&lt;/script&gt;     &lt;!-- 1番目に実行 --&gt;
  &lt;script src=&quot;/js/plugin.js&quot; defer&gt;&lt;/script&gt;     &lt;!-- 2番目に実行 --&gt;
  &lt;script src=&quot;/js/main.js&quot; defer&quot;&gt;&lt;/script&gt;      &lt;!-- 3番目に実行 --&gt;
&lt;/head&gt;</code></pre>
<h2>async 属性</h2>

<p><code>async</code> も並行ダウンロードしますが、<strong>ダウンロードが完了した順に即実行</strong>します。順序は保証されません。</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html">&lt;head&gt;
  &lt;!-- 順序不定 (依存関係があるとバグる) --&gt;
  &lt;script src=&quot;/js/jquery.js&quot; async&gt;&lt;/script&gt;
  &lt;script src=&quot;/js/plugin.js&quot; async&gt;&lt;/script&gt;  &lt;!-- jquery より先に走ることがある --&gt;
&lt;/head&gt;

&lt;!-- ✅ 単独で動く計測タグや広告タグには async が最適 --&gt;
&lt;script src=&quot;https://www.googletagmanager.com/gtag/js?id=G-XXX&quot; async&gt;&lt;/script&gt;
&lt;script src=&quot;https://connect.facebook.net/en_US/sdk.js&quot; async&gt;&lt;/script&gt;</code></pre>
<h2>type="module" (ES Modules)</h2>

<p>ES Modules (import/export を使うモジュール) は<strong>常に defer 扱い</strong>です。明示的に defer を書かなくても OK:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html">&lt;script type=&quot;module&quot; src=&quot;/js/app.mjs&quot;&gt;&lt;/script&gt;
&lt;!-- defer 相当 + strict mode + import/export 使える --&gt;

&lt;!-- インラインモジュール --&gt;
&lt;script type=&quot;module&quot;&gt;
  import { greet } from &apos;/js/lib.mjs&apos;;
  greet(&apos;world&apos;);
&lt;/script&gt;

&lt;!-- 古いブラウザ用のフォールバック --&gt;
&lt;script nomodule src=&quot;/js/legacy-bundle.js&quot;&gt;&lt;/script&gt;</code></pre>
<h2>Critical CSS との関係 (Web Vitals)</h2>

<p>Core Web Vitals の <strong>LCP (Largest Contentful Paint)</strong> 改善には、ファーストビュー描画を阻害しないことが重要です。defer / async の徹底に加え、Critical CSS のインライン化を組み合わせます:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html">&lt;head&gt;
  &lt;!-- 1. Critical CSS をインライン (ファーストビュー描画用) --&gt;
  &lt;style&gt;
    /* hero / nav の最低限のスタイル */
    body { margin: 0; font-family: sans-serif; }
    .hero { height: 60vh; background: #4a90e2; }
  &lt;/style&gt;

  &lt;!-- 2. 残りの CSS は非同期に --&gt;
  &lt;link rel=&quot;preload&quot; href=&quot;/css/main.css&quot; as=&quot;style&quot;
        onload=&quot;this.onload=null;this.rel=&apos;stylesheet&apos;&quot;&gt;
  &lt;noscript&gt;&lt;link rel=&quot;stylesheet&quot; href=&quot;/css/main.css&quot;&gt;&lt;/noscript&gt;

  &lt;!-- 3. JS は defer --&gt;
  &lt;script src=&quot;/js/app.js&quot; defer&gt;&lt;/script&gt;

  &lt;!-- 4. 計測タグは async --&gt;
  &lt;script src=&quot;/gtag.js&quot; async&gt;&lt;/script&gt;
&lt;/head&gt;</code></pre>
<h2>Resource Hints (preload/prefetch/preconnect)</h2>

<p>ヒントを使うとさらに高速化できます:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html">&lt;head&gt;
  &lt;!-- 重要 JS を早期ダウンロード開始 --&gt;
  &lt;link rel=&quot;preload&quot; href=&quot;/js/critical.js&quot; as=&quot;script&quot;&gt;

  &lt;!-- 次ページで使うリソースを先読み --&gt;
  &lt;link rel=&quot;prefetch&quot; href=&quot;/js/next-page.js&quot;&gt;

  &lt;!-- 接続だけ先に確立 --&gt;
  &lt;link rel=&quot;preconnect&quot; href=&quot;https://api.example.com&quot;&gt;
  &lt;link rel=&quot;dns-prefetch&quot; href=&quot;https://cdn.example.com&quot;&gt;

  &lt;script src=&quot;/js/critical.js&quot; defer&gt;&lt;/script&gt;
&lt;/head&gt;</code></pre>
<h2>サードパーティ JS の遅延読込</h2>

<p>チャットウィジェット・コメント欄・SNS シェアボタン等、ファーストビューに不要な JS は意図的に遅延させると Web Vitals が上がります:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-javascript">// ユーザー操作後にチャットウィジェットを読み込む
document.addEventListener(&apos;scroll&apos;, loadChat, { once: true });
document.addEventListener(&apos;click&apos;, loadChat, { once: true });

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

// または IntersectionObserver で要素が見えたとき
const obs = new IntersectionObserver((entries) =&gt; {
  if (entries[0].isIntersecting) {
    const s = document.createElement(&apos;script&apos;);
    s.src = &apos;/js/comments.js&apos;;
    document.head.appendChild(s);
    obs.disconnect();
  }
});
obs.observe(document.querySelector(&apos;#comments-section&apos;));</code></pre>
<h2>使い分け早見表</h2>

<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#e8f5e9"><th>JS の種類</th><th>推奨配置</th><th>属性</th></tr></thead>
<tbody>
<tr><td>自前のアプリケーション JS</td><td>head 内</td><td><code>defer</code></td></tr>
<tr><td>ES Modules</td><td>head 内</td><td><code>type="module"</code></td></tr>
<tr><td>GA / GTM / Facebook Pixel</td><td>head 内</td><td><code>async</code></td></tr>
<tr><td>jQuery + プラグイン</td><td>head 内</td><td><code>defer</code> (順序保持)</td></tr>
<tr><td>インライン script (極小)</td><td>head 内 or body 内</td><td>属性不要</td></tr>
<tr><td>レガシーブラウザ対応 (IE11)</td><td>body 末尾</td><td>属性なし</td></tr>
</tbody>
</table>

<h2>FAQ</h2>

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

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

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