Is it wrong to place the <script> tag after the </body> tag? [duplicate]
Asked Answered
M

10

256

How wrong is it to place the script tag after the closing tag of the body (</body>)?

<html>
  ....
  <body>
     ....
  </body>
  <script type="text/javascript" src="theJs.js"></script>
</html>
Mickiemickle answered 14/6, 2010 at 13:49 Comment(2)
Is there support for it in modern browsers.Lemures
It's not wrong. It will cause an alarm on validators, but it will run on most browsers. It is not wrong, but it is not valid.Groyne
A
217

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>
Adorno answered 14/6, 2010 at 13:53 Comment(14)
Note that apps like YSlow will actually suggest that you do include your javascript at the end of the page. It may not speed up overall load time but it may load the relevant content first. Still, putting it just inside the </body> tag is best.Scent
@epalla: if you put the script right at the end of the body tag there's no other content left to load by the time it gets there, so there should be little difference between placing it outside or just inside. You then have the added benefit of your page still validating, which was the point I was trying to make in my answer.Adorno
Yep, I was agreeing with you since your answer is good. I just wanted to add that there is a reason for putting JS at the bottom of the page instead of in the head as we've done for a long time.Scent
@AndyE Regardless of validation is there any practical issue by adding script tag after body? At least it make code cleaner im most IDEs.Succinctorium
@PHPst: well, invalid code may be subject to side effects in certain browsers. Either way, I don't see how its indentation being one tab-width less than the code above it makes it look any cleaner.Adorno
@AndyE Do you mean you do not see any issue ever? I mean cleaner when you fold the blocks.Succinctorium
@PHPst: I would expect browsers to cope with it if you really want to write your code that way. I'd still recommend writing your code to validate, however.Adorno
There is a legitimate reason for putting it after the body and for the standard to allow it in the future(possibly adding a tail tag or just allowing script tags). When the body tag is closed, the layout engine can "know" that no further html elements will change the layout and go ahead and render the page. The clearest example would be a form page with standard form submission supplemented by js. The faster rendering aspect is why YSlow and others recommend putting it after.Schlessinger
@technosaurus: there's always <script src="..." defer>, which works in all major browsers (albeit with a potentially breaking bug in IE9 and lower).Adorno
@AndyE You'll find that although it may be supported, its not always as straight forward as that. see: browserscope.org/?category=network&v=1 specifically the number of connections per host name which are affected by images, stylesheets and other sourced objects... this can be alleviated to some extent by spreading resources across different host names like css.example.com or js.example.com, but each connection still needs to be resolved and some OSes don't have builtin DNS caching and many browsers implement it poorly so you get "waiting for ..." foreverSchlessinger
@Schlessinger "YSlow and others recommend putting it after" - YSlow recommends to "Put Scripts at the Bottom", which implies at the bottom of the body element, before the closing </body> tag, not after it. https://mcmap.net/q/111396/-put-scripts-at-the-bottomEpizoon
What would be useful is if script tags had a event attribute that could be defined to determine when to parse the script. So you have event="load" event="DOMContentLoaded" for running the script after the DOM is created or event="beforeunload" on the window beforeunload event. Example, <script src="scripts/main.js" event="DOMContentLoaded"></script>. Also, if we have a head section why don't we have a tail section (or foot section)? That would solve the wait until DOM is created issues.Threemaster
Re "It won't validate": Correct. If the 'script' tag is after '</body>', HTML validation will result in "Error: Stray start tag script" (check option "source" and click "check" to see the HTML source). If it is before, it validates.Tony
it's so good that IE doesn't exist anymore.Chiekochien
E
117

Only comments and the end tag for the html element are allowed after the end tag for the body.

You can confirm this with the specification or a validator.

Browsers may perform error recovery, and the HTML specification even describes how to recover in that situation, but you should never depend on that.


It is also worth noting that the usual reason for putting the script element at the end is to ensure that elements the script may try to access via the DOM exist before the script runs.

With the arrival of the defer attribute we can place the script in the head and still get that benefit while also having the JS be downloaded by the browser in parallel with the HTML for better performance.

Epochal answered 14/6, 2010 at 13:55 Comment(2)
This is a better answer. There are too many new browsers out there with mobile coming into play to risk doing it wrong when all you have to is cut and paste a single closing tag.Riddle
Note that defer only applies to external script files (i.e. you must also specify src attribute). You cannot "defer" a <script> element that contains script.Aquinas
C
35

As Andy said, the document will be not valid, but nevertheless the script will still be interpreted. See the snippet from WebKit for example:

void HTMLParser::processCloseTag(Token* t)
{
    // Support for really broken HTML.
    // we never close the body tag, since some stupid web pages close it before
    // the actual end of the doc.
    // let's rely on the end() call to close things.
    if (t->tagName == htmlTag || t->tagName == bodyTag
                              || t->tagName == commentAtom)
        return;
    ...
Circulation answered 15/2, 2012 at 14:21 Comment(1)
"Support for really broken html." -- I think it says it all.Susette
O
9

Internet Explorer doesn't allow this any more (since version 10, I believe) and will ignore such scripts.

Firefox and Chrome still tolerate them, but there are chances that some day they will drop this as non-standard.

Olwena answered 24/7, 2013 at 22:20 Comment(1)
And yet Google does this in their example of how to do G+ sign-in, with "last updated April 10, 2014". I got it from the version for Java on the server (developers.google.com/+/quickstart/java) but presumably it is the same HTML+js for all.Cruce
M
5

Procedurally inserting an "element script" after an "element body" is a "parse error" by the recommended process by W3C. In "Tree Construction" create an error and run "tokenize again" to process that content. So it's like an additional step. Only then can it run the "Script Execution" - see the scheme process.

Anything else is a "parse error". Switch the "insertion mode" to "in body" and reprocess the token.

Technically, by the browser, it's an internal process how they mark and optimize it.

Motherinlaw answered 3/2, 2019 at 17:1 Comment(1)
Note that there are cases where the html and body start or end tags are optional. And like you said, in one case the parser ignores the ending body and html tags if there is content after them. (The body and html element end tags could be omitted without trouble; any spaces after those get parsed into the body element anyway.) See html.spec.whatwg.org/multipage/syntax.html.Threemaster
M
2

Modern browsers will take script tags in the body like so:

<body>
    <!-- main body content -->
    <script src="scripts/main.js"></script>
</body>

Basically, it means that the script will be loaded once the page has finished, which may be useful in certain cases (namely DOM manipulation). However, I highly recommend you take the same script and put it in the head tag with "defer", as it will give a similar effect.

<head>
    <script src="scripts/main.js" defer></script>
</head>
Mobile answered 2/1, 2020 at 8:9 Comment(4)
What would be useful is if script tags had a event attribute that could be defined to determine when to parse the script. So you have event="load" event="DOMContentLoaded" for running the script after the DOM is created or event="beforeunload" on the window beforeunload event. Example, <script src="scripts/main.js" event="DOMContentLoaded"></script>.Threemaster
Putting it in the head with defer doesn't have the same effect; with defer, in the head: The script is fetched asynchronously, and it’s executed only after the HTML parsing is done. Whereas if you put the script at the end of the body: The HTML parsing is done without any pauses, and when it finishes, the script is fetched, and executed.Loni
How does that answer the question? The quesion is "Is it wrong to place the <script> tag after the </body> tag?"?Tony
@PeterMortensen it's not wrong to do anything especially in something as lax as html 😂 I was referring to potentially unexpected behavior where the document hasn't actually finished loading yet depending on where you put the script tag in the body.Mobile
N
1

Yes. But if you do add the code outside it most likely will not be the end of the world since most browsers will fix it, but it is still a bad practice to get into.

Nedry answered 14/6, 2010 at 16:6 Comment(0)
T
0

You can place it like the below, or also inside the head tag is fine, but regular practice is something like just before the end of the </body> naming a comment for easy use later, and opening a <script>putting any JS inside</script></body></html>.

    <script>
      window.addEventListener('DOMContentLoaded', event => {

        // Activate Bootstrap scrollspy on the main nav element
        const sideNav = document.body.querySelector('#sideNav');
        if (sideNav) {
          new bootstrap.ScrollSpy(document.body, {
            target: '#sideNav',
            offset: 74,
          });
        };

        // Collapse responsive navbar when toggler is visible
        const navbarToggler = document.body.querySelector('.navbar-toggler');
        const responsiveNavItems = [].slice.call(
          document.querySelectorAll('#navbarResponsive .nav-link')
        );
        responsiveNavItems.map(function (responsiveNavItem) {
          responsiveNavItem.addEventListener('click', () => {
            if (window.getComputedStyle(navbarToggler).display !== 'none') {
              navbarToggler.click();
            }
          });
        });
      });
    </script>

    <!-- Bootstrap core JS-->

    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>

</body>

</html>
Time answered 11/9, 2021 at 11:34 Comment(0)
P
0

Technically you shouldn't be able to place the script tag after the body tag since rendering of the page content ends with the body (or is it the head?.)

But browsers are somewhat fault tolerant (although I wouldn't depend on this as a universal truth because you just might never know) and they'd:

  1. move the script tag back into the body tag if it appears outside the body or html tag.
  2. move the script tag into the head tag if it appears before the document declaration.
  3. leave it as is if it appears (in source order) anywhere else it appears in the document.

To be safe, you can:

  1. use the defer or async attribute with the script tag in the head, or
  2. use the script tag(s) right before the closing body tag

This norm is an accepted practice/convention and is guaranteed to remove any doubts.

Also while you are play safe and do the most [reasonable] thing, keep in mind that what you need to [then] worry about is the performance because the loading/downloading, parsing and interpretation of the internal/external sourced file(s) is/are dependent on where the script(s) tag occurs, even if you were using defer or async.

<!-- Moved (prepend) into the head -->
<script>console.log(1);
</script>
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <!-- Remains where it is -->
    <script>
        console.log(2);
    </script>
    <title>Document</title>
</head>

<body>
    <h1>Content goes here</h1>
    <!-- Remains where it is -->
    <script>
        console.log(3);
    </script>
    <h1>Content goes here</h1>

    <!-- Remains where it is -->
    <script>
        console.log(4);
    </script>
</body>

</html>
<!-- Moved (append) into the body -->
<script>
    console.log(5);
</script>
Paradies answered 18/9, 2021 at 2:36 Comment(0)
S
-1

Google actually recommends this in regards to 'CSS Optimization'. They recommend in-lining critical above-fold styles and deferring the rest (CSS file).

Example:

<html>
  <head>
    <style>
      .blue{color:blue;}
    </style>
    </head>
  <body>
    <div class="blue">
      Hello, world!
    </div>
  </body>
</html>
<noscript><link rel="stylesheet" href="small.css"></noscript>

See: Optimize CSS Delivery

Styrax answered 22/8, 2013 at 5:31 Comment(5)
You're not supposed to put stuff outside of the body element. That Google article doesn't advise anyone to do any such thing.Phelia
Im afraid that google page says actually just exact that.Lucrece
It seems like at one time, that page did recommend such a thing, but not anymore. (Now there is some dynamic loading with javascript.) The german version is not up to date and still contains the old code example.Georgetown
"element noscript" have to be by RFC inside "element html" and "element body" tooMotherinlaw
If using a CSP for security, you probably don't want CSS in your HTML fileSophocles

© 2022 - 2024 — McMap. All rights reserved.