Is it wrong to place the – mapto Jan 20 '19 at 11:21

11 Answers11

209

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>
Glorfindel
  • 20,880
  • 13
  • 75
  • 99
Andy E
  • 326,646
  • 82
  • 467
  • 441
  • 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

    tag is best.

    – Matt Brunmeier Jun 14 '10 at 16:12
  • 14
    @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. – Andy E Jun 14 '10 at 16:19
  • 1
    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. – Matt Brunmeier Jun 14 '10 at 16:34
  • @AndyE Regardless of validation is there any practical issue by adding script tag after `body`? At least it make code cleaner im most IDEs. – Handsome Nerd May 01 '13 at 12:22
  • 3
    @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. – Andy E May 01 '13 at 12:48
  • @AndyE Do you mean you do not see any issue ever? I mean cleaner when you fold the blocks. – Handsome Nerd May 01 '13 at 13:54
  • 1
    @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. – Andy E May 02 '13 at 10:18
  • 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. – technosaurus Dec 11 '14 at 10:16
  • 1
    @technosaurus: there's always ` – Andy E Dec 11 '14 at 11:48
  • @AndyE You'll find that although it may be supported, its not always as straight forward as that. see: http://www.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 ..." forever – technosaurus Dec 11 '14 at 12:34
  • @technosaurus "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 `

    ` tag, not after it. http://stackoverflow.com/questions/4948278/put-scripts-at-the-bottom

    – MrWhite Jul 08 '15 at 15:06
  • 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, ``. 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. – 1.21 gigawatts Jan 24 '20 at 11:09
  • Re *"It won't validate"*: Correct. If the 'script' tag is ***after*** '

    ', [HTML validation](https://pmortensen.eu/temp2/script_tag_after_ending_body_tag_but_before_ending_html_tag.html) will result in *"[Error: Stray start tag script](https://validator.w3.org/nu/?doc=http%3A%2F%2Fpmortensen.eu%2Ftemp2%2Fscript_tag_after_ending_body_tag_but_before_ending_html_tag.html)"* (check option *"source"* and click *"check"* to see the HTML source). If it is ***before***, [it validates](https://pmortensen.eu/temp2/script_tag_before_ending_body_tag.html).

    – Peter Mortensen Nov 22 '21 at 03:53
107

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.

Quentin
  • 857,932
  • 118
  • 1,152
  • 1,264
  • 15
    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. – Erik Reppen Mar 29 '12 at 20:29
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;
    ...
Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Vitalii Fedorenko
  • 104,478
  • 28
  • 147
  • 111
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.

Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Bronx
  • 719
  • 8
  • 11
  • 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 (https://developers.google.com/+/quickstart/java) but presumably it is the same HTML+js for all. – Tom Apr 15 '14 at 17:10
3

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.

Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
BGBRUNO
  • 5,819
  • 5
  • 39
  • 47
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.

Taylor Satula
  • 526
  • 1
  • 5
  • 20
0

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

Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Donald Porter
  • 543
  • 4
  • 4
  • 10
    You're not supposed to put stuff outside of the `body` element. That Google article doesn't advise anyone to do any such thing. – ChaseMoskal Aug 16 '14 at 22:35
  • 2
    Im afraid that google page says actually just exact that. – 10us Sep 28 '15 at 14:38
  • 8
    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. – bodo Feb 04 '16 at 17:05
  • 1
    "element noscript" have to be by RFC inside "element html" and "element body" too – BGBRUNO Feb 03 '19 at 16:04
  • If using a CSP for security, you probably don't want CSS in your HTML file – Charles L. Jan 14 '22 at 01:57
0

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>
Ad Charity
  • 67
  • 1
  • 3
  • 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, ``. – 1.21 gigawatts Jan 24 '20 at 11:06
  • 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. – nCardot Mar 21 '21 at 15:30
  • How does that answer the question? The quesion is *"Is it wrong to place the – Peter Mortensen Nov 22 '21 at 04:05
  • @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. – Ad Charity Jan 29 '22 at 08:54
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/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"></script>

</body>

</html>
Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
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>
-1

 <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/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"></script>

Always end with a body tag and make sure every single JavaScript part is within the body tag. You can also have links or scripts inside head tags, but it is not recommended unless you are really certain your JavaScript code is too big to have it inline.

Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124