I have encountered the issue you mentioned in this specific manner:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Test</title>
<script src="./test.js"></script>
</head>
<body>
</body>
</html>
The problem arises when running the script, causing a pause in the parsing process. As a result, only elements that have been parsed up to that point are available. Essentially, only these sections have been processed:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Test</title>
<script src="./test.js"></script>
At this stage, there is no <body>
tag that has been parsed for the script to act upon. So, when trying to access document.body
, the output is null
. Attempting to modify document.body.style
will result in an error, triggering a message (
Uncaught TypeError: Cannot read properties of null (reading 'style')
at
test.js:11:17
) instead of changing the color as intended.
To address this issue, one solution is to relocate your script after the <body>
tag, like so:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Test</title>
</head>
<body>
<script src="./test.js"></script>
</body>
</html>
Alternatively, you can add the defer
attribute to your script tag, allowing the parser to wait until the body content is fully loaded.
<!DOCTYPE html>
<html lang="en">
<head>
<title>Test</title>
<script src="./test.js" defer></script>
</head>
<body>
</body>
</html>
There is also the option of using the async
attribute for scripts that do not cause immediate pausing of the parser. However, in this case, it may not be suitable due to potential race conditions affecting the order of execution. The parser usually reaches the <body>
element faster than fetching and executing a separate JavaScript file.
This post elaborates on the distinctions between regular script loading, async, and defer attributes: