Is it wrong to place the – 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
  • it's so good that IE doesn't exist anymore. – Fed Jun 27 '22 at 10:43
  • 116

    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
    • 914,110
    • 126
    • 1,211
    • 1,335
    • 16
      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
    • 2
      Note that `defer` ***only*** applies to external script files (i.e. you must also specify `src` attribute). You cannot *"defer"* a ` – Ian Boyd Aug 03 '22 at 18:09
    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,738
    • 21
    • 105
    • 131
    Vitalii Fedorenko
    • 110,878
    • 29
    • 149
    • 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,738
    • 21
    • 105
    • 131
    Bronx
    • 747
    • 8
    • 12
    • 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
    4

    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,738
    • 21
    • 105
    • 131
    Bruno
    • 6,623
    • 5
    • 41
    • 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
    • 520
    • 1
    • 5
    • 20
    1

    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>
    
    • 1
      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. –  Jan 29 '22 at 08:54
    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,738
    • 21
    • 105
    • 131
    Donald Porter
    • 553
    • 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 – Bruno 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

    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,738
    • 21
    • 105
    • 131
    Kush P
    • 1
    • 1
    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>