Style and Script Tags in HTML Body... Why Not

style and script tags in HTML body... why not?

Although the specs explicitly state style tags are not permitted in the body tag, specs aren't all that matters. Style tags are supported in the body by every major browser, and that's ultimately how users see your site.* While there has long been a drive for better standards and standards support in the browser industry, there's also long been a general push to render broken documents as well as can be.

Google, who leads the HTML5 spec effort, simultaneously maintains google.com which violates specs to save bytes, by leaving the quotes out of its attribute values, using selector hacks against the CSS spec, including script tags with no type or language, and link tags with no type. A purist could argue one of the most used sites on the internet is violating the specs and in serious danger of being horribly misrendered. Or, we can reason that no browser will enter popular use that can't render such widely used hacks on the spec.

So, the question is more of which way the browser industry is going - which again is one of both better specs, but also doing their best to honor the intent of pages that violate those specs. My bet is style tags will keep working in the body for a long time to come.

*As of this writing, style tags in the body are supported with an HTML5 doctype in Firefox 3+, IE6+, Safari 2+, Chrome 12+. Support likely goes back farther but those browsers are rarely seen on the interwebs.

Where should I put script tags in HTML markup?

Here's what happens when a browser loads a website with a <script> tag on it:

  1. Fetch the HTML page (e.g. index.html)
  2. Begin parsing the HTML
  3. The parser encounters a <script> tag referencing an external script file.
  4. The browser requests the script file. Meanwhile, the parser blocks and stops parsing the other HTML on your page.
  5. After some time the script is downloaded and subsequently executed.
  6. The parser continues parsing the rest of the HTML document.

Step #4 causes a bad user experience. Your website basically stops loading until you've downloaded all scripts. If there's one thing that users hate it's waiting for a website to load.

Why does this even happen?

Any script can insert its own HTML via document.write() or other DOM manipulations. This implies that the parser has to wait until the script has been downloaded and executed before it can safely parse the rest of the document. After all, the script could have inserted its own HTML in the document.

However, most JavaScript developers no longer manipulate the DOM while the document is loading. Instead, they wait until the document has been loaded before modifying it. For example:

<!-- index.html -->
<html>
<head>
<title>My Page</title>
<script src="my-script.js"></script>
</head>
<body>
<div id="user-greeting">Welcome back, user</div>
</body>
</html>

JavaScript:

// my-script.js
document.addEventListener("DOMContentLoaded", function() {
// this function runs when the DOM is ready, i.e. when the document has been parsed
document.getElementById("user-greeting").textContent = "Welcome back, Bart";
});

Because your browser does not know my-script.js isn't going to modify the document until it has been downloaded and executed, the parser stops parsing.

Antiquated recommendation

The old approach to solving this problem was to put <script> tags at the bottom of your <body>, because this ensures the parser isn't blocked until the very end.

This approach has its own problem: the browser cannot start downloading the scripts until the entire document is parsed. For larger websites with large scripts and stylesheets, being able to download the script as soon as possible is very important for performance. If your website doesn't load within 2 seconds, people will go to another website.

In an optimal solution, the browser would start downloading your scripts as soon as possible, while at the same time parsing the rest of your document.

The modern approach

Today, browsers support the async and defer attributes on scripts. These attributes tell the browser it's safe to continue parsing while the scripts are being downloaded.

async

<script src="path/to/script1.js" async></script>
<script src="path/to/script2.js" async></script>

Scripts with the async attribute are executed asynchronously. This means the script is executed as soon as it's downloaded, without blocking the browser in the meantime.
This implies that it's possible that script 2 is downloaded and executed before script 1.

According to http://caniuse.com/#feat=script-async, 97.78% of all browsers support this.

defer

<script src="path/to/script1.js" defer></script>
<script src="path/to/script2.js" defer></script>

Scripts with the defer attribute are executed in order (i.e. first script 1, then script 2). This also does not block the browser.

Unlike async scripts, defer scripts are only executed after the entire document has been loaded.

According to http://caniuse.com/#feat=script-defer, 97.79% of all browsers support this. 98.06% support it at least partially.

An important note on browser compatibility: in some circumstances, Internet Explorer 9 and earlier may execute deferred scripts out of order. If you need to support those browsers, please read this first!

(To learn more and see some really helpful visual representations of the differences between async, defer and normal scripts check the first two links at the references section of this answer)

Conclusion

The current state-of-the-art is to put scripts in the <head> tag and use the async or defer attributes. This allows your scripts to be downloaded ASAP without blocking your browser.

The good thing is that your website should still load correctly on the 2% of browsers that do not support these attributes while speeding up the other 98%.

References

  • async vs defer attributes
  • Efficiently load JavaScript with defer and async
  • Remove Render-Blocking JavaScript
  • Async, Defer, Modules: A Visual Cheatsheet

SEO implications of including style and script tags inside body?

It's just bad practice to do so. HTML is only used for semantically marking up the data on the page.

Styles are for defining how this data LOOKS.

Script is for defining how the page BEHAVES.

The three should be separated / coupled loosely.

As for SEO, I doubt it has any effect at all.

Is it wrong to place the script tag after the /body tag?

It won't validate outside of the <body> or <head> tags. It also won't make much difference — unless you're doing DOM manipulations that could break IE before the body element is fully loaded — to putting it just before the closing </body>.

<html>
....
<body>
....
<script type="text/javascript" src="theJs.js"></script>
</body>
</html>

HTML5: Why does a script tag need to be placed at the end of body tag instead of at the beginning of the body tag?

JavaScript loading isn't part of the DOM, but it's blocking and it will interrupt the loading process until it's done. Even if it's a small script, it's still an extra request and will slow down the whole process.

The truth is browsers only need the DOM structure to start rendering. They don't need the scripts nor do they count for layout purposes. They are just dead weight until they are executed.

Even CSS could be considered unnecessary for the initial rendering process (more or less), but since CSS loading is non-blocking, this isn't an issue.

The performance gain from putting scripts at the bottom can vary, and even if it's a recommended practice, it might not always be harmless. When dealing with CMSes, for example, you might design your theme to load the scripts at the bottom, but you have no control over plugins. This happens a lot with WordPress, for example, and people end up putting script in the head to avoid conflicts with plugins.

Bonus Track

When in comes to tracking scripts, such as mixpanel, inspectlet, even Google Analytics... you might want to detect when a user enters your page and leaves a few seconds later due to slow loading times, an adult advertising block... whatever.

If you put the tracking script and the bottom it might not be able to boot in time to detect that visit, so you won't know you have such an extreme bounce rate. In this case I'd consider putting the script in the head.

If you put resource hints at the beginning, say

<link rel="preconnect" href="https://api.mixpanel.com" />
<link rel="preconnect" href="https://cdn.mxpnl.com/" />

Or

<link rel="prefetch" href="https://cdn.mxpnl.com/libs/mixpanel-2-latest.min.js" as="script">

It would mitigate the drawback of loading said scripts in the head.

When should script tags be visible and why can they?

The HTML5 specification defines a style sheet that user agents (like browsers) are expected to use. Section 10.3.1 lists the styles for "Hidden elements":

@namespace url(http://www.w3.org/1999/xhtml);

[hidden], area, base, basefont, datalist, head, link,
meta, noembed, noframes, param, rp, script, source, style, template, track, title {
display: none;
}

embed[hidden] { display: inline; height: 0; width: 0; }

As you can see, it applies display: none; to script.

This is the only "barrier" between your users and hidden script elements. It’s perfectly fine and intended to be able to overwrite styles from user-agent style sheets within author style sheets (and of course also within user style sheets).

Why someone might want to use it? One use case is displaying content without having to escape characters like </>, similar to the old xmp element. The script element can be used not only for scripts, but also for data blocks (i.e., for anything with a MIME type).

Does the script tag position in HTML affects performance of the webpage?

Javascript assets, by default, tend to block any other parallel downloads from occurring. So, you can imagine if you have plenty of <script> tags in the head, calling on multiple external scripts will block the HTML from loading, thus greeting the user with a blank white screen, because no other content on your page will load until the JS files have completely loaded.

In order to combat this issue, many developers have opted to placing JS at the bottom of the HTML page (before the </body> tag). This seems logical because, most of the time JS is not required until the user begins interacting with the site. Placing JS files at the bottom also enables progressive rendering.

Alternatively, you can choose to load Javascript files asynchronously. There are plenty of existing methods which this can be accomplished by:

XHR Eval

var xhrObj = getXHRObject();
xhrObj.onreadystatechange =
function() {
if ( xhrObj.readyState != 4 ) return;
eval(xhrObj.responseText);
};
xhrObj.open('GET', 'A.js', true);
xhrObj.send('');

Script DOM Element

var se = document.createElement('script');
se.src = 'http://anydomain.com/A.js';
document.getElementsByTagName('head')
[0].appendChild(se);

Meebo Iframed JS

var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
var doc = iframe.contentWindow.document;
doc.open().write('<body onload="insertJS()">');
doc.close();

To name a few...

Note: Only a maximum of five scripts can be loaded in parallel in current browsers.


ForIE there is the defer attribute you can use like so:

<script defer src="jsasset.js" type="text/javascript"></script>

When set, this boolean attribute
provides a hint to the user agent that
the script is not going to generate
any document content (e.g., no
"document.write" in javascript) and
thus, the user agent can continue
parsing and rendering.

Update 2022: all browsers now accept the defer attribute.



Related Topics



Leave a reply



Submit