在body的结束标记(</body>)之后放置脚本标记有多错误?

<html>
  ....
  <body>
     ....
  </body>
  <script type="text/javascript" src="theJs.js"></script>
</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>

其他回答

是的。但是,如果您确实在外部添加了代码,这很可能不会是世界末日,因为大多数浏览器都会修复它,但这仍然是一个不好的做法。

只有html元素的注释和结束标记被允许放在主体的结束标记之后。

您可以通过规范或验证器确认这一点。

浏览器可以执行错误恢复,HTML规范甚至描述了在这种情况下如何恢复,但您永远不应该依赖于此。


还值得注意的是,将脚本元素放在末尾的通常原因是确保脚本在运行之前可能试图通过DOM访问的元素已经存在。

随着defer属性的到来,我们可以将脚本放在头部,同时还可以让浏览器在下载HTML的同时下载JS,以获得更好的性能。

正如Andy所说,文档将是无效的,但是脚本仍然会被解释。请看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;
    ...

它不会在<body>或<head>标记之外进行验证。把它放在</body>结束之前也不会有太大区别——除非你在做DOM操作,可能会在body元素完全加载之前破坏IE。

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

从技术上讲,您不应该将脚本标记放在主体标记之后,因为页面内容的呈现以主体结束(或者是头部?)

但是浏览器在某种程度上是容错的(尽管我不认为这是一个普遍的真理,因为你可能永远不会知道),他们会:

如果脚本标记出现在正文或HTML标记之外,则将脚本标记移回正文标记。 如果脚本标记出现在文档声明之前,则将它移动到head标记中。 如果它出现在文档中出现的其他地方(按源代码顺序),则保持原样。

为了安全起见,你可以:

在头部的脚本标记中使用defer或async属性,或者 在结束主体标记之前使用脚本标记

此规范是公认的惯例,保证消除任何疑问。

另外,当你在安全的情况下做最合理的事情时,请记住你需要担心的是性能,因为内部/外部源文件的加载/下载、解析和解释依赖于脚本标记出现的位置,即使你使用的是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>