將 <script>
標籤放在 <body>
的底部,即 </body>
結束標籤之前,和放在 </body>
之後,主要區別在於瀏覽器解析和渲染頁面的方式,以及這會如何影響使用者體驗。
1. <script>
在 </body>
之前(推薦):
- 瀏覽器解析: 瀏覽器解析 HTML 文件是自上而下的。當遇到
<script>
標籤時,會暫停 HTML 解析,下載並執行 JavaScript 程式碼。 將指令碼放在</body>
之前意味著在解析完頁面主要內容(HTML 結構)之後才會執行指令碼。 - 渲染: 這允許瀏覽器先渲染頁面內容,使用者可以更快地看到頁面,即使指令碼仍在下載或執行。這改善了使用者體驗,特別是對於包含大量 JavaScript 或網路連線較慢的使用者。
- DOMContentLoaded 事件: 所有HTML解析完畢後會觸發
DOMContentLoaded
事件。放在</body>
結束標籤之前的指令碼會在DOMContentLoaded
事件觸發之前執行,這意味著指令碼可以訪問所有 DOM 元素。
2. <script>
在 </body>
之後:
- 瀏覽器解析: 與之前類似,瀏覽器會暫停 HTML 解析來下載和執行指令碼。 不同的是,此時整個 HTML 文件(包括
</body>
)都已經解析完畢。 - 渲染: 由於指令碼在 HTML 解析完成後才執行,因此頁面渲染可能會被阻塞,直到指令碼下載和執行完畢。如果指令碼很大或網路連線慢,使用者可能會看到空白頁面或未完全載入的頁面,導致糟糕的使用者體驗。
- load 事件: 放在
</body>
結束標籤之後的指令碼會在load
事件觸發之前執行。load
事件在頁面完全載入所有資源(包括圖片、樣式表等)後觸發。
總結:
幾乎所有情況下,都應該將 <script>
標籤放在 </body>
結束標籤之前。 這確保了瀏覽器可以儘快渲染頁面內容,提供更好的使用者體驗。 只有在某些特殊情況下,例如指令碼需要在所有頁面資源載入完成後才執行,才需要將指令碼放在 </body>
之後。 即使在這種情況下,也建議使用 defer
或 async
屬性來最佳化指令碼載入和執行,避免阻塞頁面渲染。
defer
和 async
屬性:
defer
: 使用defer
屬性的指令碼會在 HTML 解析完成後,DOMContentLoaded 事件觸發之前執行。指令碼會按它們在 HTML 中出現的順序執行。async
: 使用async
屬性的指令碼會非同步下載和執行,不會阻塞 HTML 解析。指令碼執行的順序不確定,哪個先下載完哪個先執行。
示例:
<!DOCTYPE html>
<html>
<head>
<title>Script Tag Placement</title>
</head>
<body>
<h1>My Website</h1>
<p>Some content here.</p>
<script src="script1.js" defer></script> <!-- 推薦做法 -->
<script src="script2.js" async></script> <!-- 非同步載入 -->
</body>
</html>
在這個例子中,script1.js
會在 HTML 解析完成後,DOMContentLoaded 事件觸發之前執行,而 script2.js
會非同步載入和執行。
總之,為了最佳效能和使用者體驗,請將指令碼放在 </body>
結束標籤之前,並根據需要使用 defer
或 async
屬性。