简体   繁体   English

是不是放错了<script> tag after the </body> tag?

[英]Is it wrong to place the <script> tag after the </body> tag?

How wrong is it to place the script tag after the closing tag of the body ( </body> )?将脚本标签放在正文( </body> )的结束标签之后有多大的错误?

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

It won't validate outside of the <body> or <head> tags.它不会在<body><head>标记之外进行验证 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> .它也不会有太大的区别——除非你正在做的 DOM 操作可能会在 body 元素完全加载之前破坏 IE——把它放在关闭</body>之前。

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

Only comments and the end tag for the html element are allowed after the end tag for the body.在正文的结束标记之后,只允许html元素的注释和结束标记。

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.浏览器可能会执行错误恢复,HTML 规范甚至描述了如何在这种情况下恢复,但你永远不应该依赖它。


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.还值得注意的是,将脚本元素放在末尾的通常原因是确保脚本可能尝试通过 DOM 访问的元素在脚本运行之前存在。

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.随着defer属性的到来,我们可以将script放在头部并仍然获得好处,同时还可以让浏览器与 HTML 并行下载 JS 以获得更好的性能。

As Andy said , the document will be not valid, but nevertheless the script will still be interpreted.正如安迪所说,该文件将无效,但脚本仍将被解释。 See the snippet from WebKit for example:例如,请参阅 WebKit 的片段

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;
    ...

Internet Explorer doesn't allow this any more (since version 10 , I believe) and will ignore such scripts. Internet Explorer 不再允许这样做(我相信从版本 10开始)并将忽略此类脚本。

Firefox and Chrome still tolerate them, but there are chances that some day they will drop this as non-standard. Firefox 和 Chrome 仍然可以容忍它们,但有可能有一天它们会将其作为非标准而放弃。

Procedurally inserting an "element script" after an "element body" is a "parse error" by the recommended process by W3C .根据 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.将“插入模式”切换为“in body”并重新处理令牌。

Technically, by the browser, it's an internal process how they mark and optimize it.从技术上讲,对于浏览器来说,这是他们如何标记和优化它的内部过程。

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.但是如果你确实在外面添加代码,它很可能不会是世界末日,因为大多数浏览器都会修复它,但这仍然是一个不好的做法。

Google actually recommends this in regards to 'CSS Optimization'. Google 实际上就“CSS 优化”推荐了这一点。 They recommend in-lining critical above-fold styles and deferring the rest (CSS file).他们建议内联关键的折叠样式并推迟其余样式(CSS 文件)。

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请参阅: 优化 CSS 交付

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).基本上,这意味着脚本将在页面完成后加载,这在某些情况下(即 DOM 操作)可能很有用。 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.但是,我强烈建议您使用相同的脚本并将其放在带有“defer”的头部标签中,因为它会产生类似的效果。

<head>
    <script src="scripts/main.js" defer></script>
</head>

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> .你可以像下面这样放置它,或者也可以放在 head 标签内,但通常的做法是在 </body> 结束之前命名一个注释以便以后使用,然后打开一个<script> 放置任何 JS里面</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>

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.如果脚本标签出现在 body 或 html 标签之外,则将其移回 body 标签中。
  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在头部使用带有 script 标签的deferasync属性,或者
  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.此外,当您安全行事并做最 [合理] 的事情时,请记住,您需要 [然后] 担心的是性能,因为内部/外部源文件的加载/下载、解析和解释is/are 取决于 script(s) 标签出现的位置,即使您使用的是 defer 或 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>

 <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.始终以body标签结尾,并确保每个 JavaScript 部分都在body标签内。 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.您也可以在head标记中包含链接或脚本,但除非您确实确定您的 JavaScript 代码太大而无法内联,否则不建议这样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM