JavaScriptはHTMLにscriptタグを使ったり外部ファイルを読み込んで実行しますが、その記述場所はhead内やbody内の最下部です。そのどこがいいのでしょうか?
JavaScriptの記述場所
HTMLにJavaScriptを記述するのは、headタグ内もしくはbodyタグ内となります。
どちらの場所でも外部ファイルを読み込むこともscriptタグを使って記述することもできます。
head内の記述例)
<html lang="ja">
<head>
<meta charset="UTF-8">
<script src="sample.js"></script>
<script>
let items = ['Hello Everybody!', 'Good Bye!'];
for (let i = 0; i < items.length; i++) {
console.log(items[i]);
}
</script>
</head>
<body>
<p id="show"></p>
</body>
</html>
body内に記述するときは基本的にタグの最下部に記述します。
body内記述例)
<html lang="ja">
<head>
<meta charset="UTF-8">
</head>
<body>
<p id="show"></p>
<script src="sample.js"></script>
<script>
let items = ['Hello Everybody!', 'Good Bye!'];
for (let i = 0; i < items.length; i++) {
console.log(items[i]);
}
</script>
</body>
</html>
HTMLがWebブラウザに読み込まれて画面に表示されるまでにDOMのレンダリングを行います。
DOMのレンダリングはHTMLソースの上から下へ順番に処理していきます。
なのでHTMLを表示するときは、まずheadタグ内を処理してからその後bodyタグ内を処理して画面に表示します。
もしheadタグ内にJavaScriptを記述してるときは、JavaScriptの処理をしてからbodyタグ内を処理します。
JavaScriptが外部ファイルであった場合はファイルの読み込み(ダウンロード)をしてからbodyタグ内を処理します。
bodyタグ内の最下部にJavaScriptを記述しているときは、bodyタグ内のJavaScriptの記述前の処理をしたあとにJavaScriptの処理をします。
このように記述する場所によってJavaScriptで記述した内容を処理するタイミングが変わります。
そこで、「どこにJavaScriptを記述するのがいいのか」をインターネットで検索すると様々な見解を読むことができます。
その中でもbodyタグ内の最下部に記述することをおすすめている記事が多いように思います。
理由としては、headタグ内に記述するとbodyタグ内の処理を行う前にJavaScriptの記述を処理する(外部ファイルの場合はファイルの読み込みをする)ため表示に時間がかかるのが主な理由となっています。
他には、JavaScriptでbodyタグ内のElementオブジェクトを処理する場合に、headタグ内にJavaScriptを記述するとまだbodyタグ内の処理が行われていないので、Elementオブジェクトが処理できずにエラーとなるためです。
以下はその例です。
例)
<html lang="ja">
<head>
<meta charset="UTF-8">
<script>
let hello = document.getElementById('show');
hello.textContent = 'ハロー!';
</script>
</head>
<body>
<p id="show"></p>
</body>
</html>
このコードは、script処理するときにはbodyタグ内の処理が行われていないためpタグがまだ無いのでエラーとなります。
この場合は以下のように記述します。
例)
<html lang="ja">
<head>
<meta charset="UTF-8">
</head>
<body>
<p id="show"></p>
<script>
let hello = document.getElementById('show');
hello.textContent = 'ハロー!';
</script>
</body>
</html>
そして逆に、JavaScriptでbodyタグ内の処理が行われる前に処理をしたい内容がある場合、言い換えればbodyタグ内のElementオブジェクトを処理しない場合はhead内に記述したいかもしれません。
つまり、簡単な結論を言ってしまうと、JavaScript記述は処理内容に応じてhead内かbody内に記述を選ぶべきです。
ですが、記述が煩雑になったり整理や管理ができないなどの理由で、head内かbody内のどちらかに統一したいといった要望はあるかと思います。
そこでどちらに記述しても動作する方法と、できるだけ動作に悪影響を及ぼさない方法を説明します。
HTMLタグ属性による調整
前述のようにJavaScriptはscriptタグにより記述されます。
直接ソースコードを記述する場合も外部ファイルを読み込む場合もscriptタグを使用します。
このタグの属性を使ってレンダリングの処理とJavaScriptの処理を非同期にしたり、JavaScriptの処理を遅らせたりできます。
例)
<script src="sample.js" async></script>
async属性は非同期に対象スクリプトの読み込みと実行をします。
例)
<script src="sample.js" defer></script>
defer属性は対象スクリプトの読み込み後、実行はDOMのレンダリング後に行います。
これら属性を使うことでhead内に記述しても動作に悪影響を及ぼさずにbody内で記述したときと同じ結果を出しパフォーマンスの向上が期待できます。
JavaScriptコード内で調整
ソースコード内で画面が読み込まれたときに処理を実行するように記述すれば、head内にscriptを記述してもDOMのレンダリング後にその処理は実行できます。
例)
window.onload = () => {
let hello = document.getElementById('show');
hello.textContent = 'ハロー!';
}
先程の例でhead内で記述するとエラーになっていたのも、画面が読み込まれたときに実行するような記述方法にするとhead内に記述しても正しく実行されます。
この「window.onload」は一般的によく見る書き方で、古くから使われています。
ただし、この記述方法だと複数の記述があった場合は最後に記述したイベントだけが実行されます。
例)
window.onload = () => {
console.log('朝');
}
window.onload = () => {
console.log('昼');
}
window.onload = () => {
console.log('夜');
}
この場合はコンソールに「夜」だけが表示されます。
なので現在では「addEventListener」を使った方法が主流になっています。
例)
window.addEventListener('load', () => {
console.log('朝');
})
window.addEventListener('load', () => {
console.log('昼');
})
window.addEventListener('load', () => {
console.log('夜');
})
こうするとコンソールには「朝」「昼」「夜」が表示されます。
さらにDOMのレンダリング後にフォーカスしてloadイベントを処理する場合、DOMContentLoadedイベントがより速く処理を行います。
例)
window.addEventListener('load', () => {
console.log('朝');
})
window.addEventListener('load', () => {
console.log('昼');
})
window.addEventListener('DOMContentLoaded', () => {
console.log('夜');
})
この場合はコンソールに「夜」「朝」「昼」の順番で表示されます。
DOMContentLoadedイベントのほうが処理が速いということですね。
こうやってイベント処理をコードに実装することで、実行タイミングをコントロールできるので、head内であってもbody内であってもどちらでも正しく動作できます。
まとめ
よく見る記事にはJavaScriptはbodyタグ内の最下部に書きましょうとありますが、JavaScriptの処理内容や状況に応じて工夫してhead内やbody内のどちらに記述してもいいのではないでしょうか。