把<script>标签放在</body>标签后面是错误的吗?

255

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

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

1
现代浏览器是否支持它? - Xdrone
这不是错误。它会在验证器上引起警报,但它可以在大多数浏览器上运行。它不是错误,但也不是有效的。 - KHAYRI R.R. WOULFE
10个回答

217
它只能在 <body><head> 标签内进行 验证。除非您在 body 元素完全加载之前进行 DOM 操作可能会 破坏 IE,否则将其放置在关闭的 </body> 标签之前也不会有太大的区别。
<html>
  ....
  <body>
     ....
     <script type="text/javascript" src="theJs.js"></script>
  </body>
</html>

15
如果您将脚本放在body标签的末尾,那么在它到达那里之前就不会加载任何其他内容,因此将其放在外部或内部应该没有太大区别。您还可以获得额外的好处,即您的页面仍然可以通过验证,这是我在回答中试图说明的要点。 - Andy E
1
没错,我同意你的答案很好。我只是想补充一下,将JS放在页面底部而不是头部是有原因的,虽然我们已经这样做了很长时间。 - Matt Brunmeier
3
@PHPst: 嗯,在某些浏览器中,无效的代码可能会导致副作用。无论如何,我并不认为它的缩进比上面的代码少一个制表符能让它看起来更清晰易读。 - Andy E
1
@PHPst:如果你真的想以那种方式编写代码,我认为浏览器应该能够处理它。然而,我仍然建议编写验证代码。 - Andy E
1
@technosaurus:始终有<script src="..." defer>,它适用于所有主要浏览器(尽管在IE9及以下版本中可能存在潜在的错误)。 - Andy E
显示剩余9条评论

117

在body标签结束后,只允许使用注释和html元素的结束标签。

您可以通过规范验证器进行确认。

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


值得注意的是,将脚本元素放在末尾的通常原因是确保脚本尝试通过DOM访问的元素在脚本运行之前存在。
随着defer属性的到来,我们可以将script放在head中,仍然可以获得该好处,同时使JS与HTML并行下载以提高性能。

16
这是一个更好的答案。现在有太多新的浏览器出现,移动浏览器也越来越普及,如果做错了,就会很麻烦。所以,只需复制并粘贴一个单一的闭合标签,就可以避免这种风险。 - Erik Reppen
2
请注意,defer 仅适用于外部脚本文件(即您还必须指定 src 属性)。您不能将包含脚本的 <script> 元素“延迟”。 - Ian Boyd

35

正如安迪所说,该文档将无效,但脚本仍将被解释执行。例如,可以查看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;
    ...

13
支持真正损坏的HTML。 -- 我认为这句话已经说得很清楚了。 - Diogo Kollross

9

自从 10 版本后,Internet Explorer不再支持此类脚本,并将忽略它们。

Firefox 和 Chrome 仍然兼容这些脚本,但未来有可能会将其标记为非标准内容而不再支持。


1
然而,Google在他们的G+登录示例中使用了这种方法,"最后更新于2014年4月10日"。我是从服务器上Java版本(https://developers.google.com/+/quickstart/java)获取的,但所有HTML+js都应该是相同的。 - Tom

5
在W3C的推荐流程中,"元素脚本"在"元素主体"后进行程序插入是一个"解析错误"。在"树构建"中创建一个错误并运行"再次标记化"以处理该内容。所以这就像是一个额外的步骤。只有这样才能运行"脚本执行" - 参见方案过程

其他任何操作都是"解析错误"。将"插入模式"切换到"在主体内"并重新处理令牌。

从浏览器技术上讲,它是如何标记和优化的内部过程。

请注意,html和body标签的开始和结束标签是可选的。就像你所说的,在某些情况下,如果它们之后还有内容,解析器会忽略结束的body和html标签。(body和html元素的结束标签可以省略,不会有任何问题;不管有没有空格,它们之后的内容都会被解析为body元素。)请参考https://html.spec.whatwg.org/multipage/syntax.html。 - undefined

1
现代浏览器将在 body 中使用 script 标签,如下所示:
<body>
    <!-- main body content -->
    <script src="scripts/main.js"></script>
</body>

基本上,这意味着脚本将在页面加载完成后加载,这在某些情况下可能非常有用(即DOM操作)。然而,我强烈建议您使用“defer”将相同的脚本放在头标签中,因为它会产生类似的效果。
<head>
    <script src="scripts/main.js" defer></script>
</head>

1
有用的是如果script标签有一个event属性,可以定义来确定何时解析脚本。因此,您可以使用event="load" event="DOMContentLoaded"在DOM创建后运行脚本或在窗口beforeunload事件上使用event="beforeunload"。例如,<script src="scripts/main.js" event="DOMContentLoaded"></script> - 1.21 gigawatts
使用defer将脚本放在head中并不会产生相同的效果;使用defer放置在head中:脚本会异步获取,并且只有在HTML解析完成后才会执行。而如果将脚本放在body的末尾:HTML解析将不会有任何暂停,当它完成时,脚本会被获取并执行。 - nCardot
那怎么回答问题呢?问题是“在</body>标签之后放置<script>标签是否有错?” - Peter Mortensen
@PeterMortensen,特别是在像HTML这样宽松的东西中做任何事情都不是错误的。我指的是可能出现意外行为的情况,具体取决于您在body中放置脚本标记的位置,因为文档尚未完全加载。 - user11736156

1

是的。但如果你将代码添加到它之外,大多数浏览器可能会自动修复,但这仍然是一个不好的习惯。


0

您可以将其放置在下面,或者也可以放在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>

0

从技术上讲,在body标签之后放置脚本标签是不正确的,因为页面内容的呈现是以body(或者是head)结束的。

但是浏览器有一定的容错性(尽管我不会把它作为普遍真理,因为你永远不知道),它们会:

  1. 把出现在body或html标签外的脚本标签移回到body标签内。
  2. 将出现在文档声明之前的脚本标签移到head标签中。
  3. 如果出现在文档中的任何其他位置(按源代码的顺序),则保持不变。

为确保安全起见,您可以:

  1. 在head中使用deferasync属性与脚本标签配合使用,或者
  2. 在即将关闭的body标签之前直接使用脚本标签。

这种规范是被广泛接受的做法/约定,并且可以消除任何疑虑。

当你保持安全并做最合理的事情时,也请记住需要担心的是性能,因为内部/外部源文件的加载/下载、解析和解释取决于脚本标记的发生位置,即使你使用了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>

-1

谷歌在“CSS优化”方面实际上推荐这样做。他们建议将关键的以上折叠样式内联,而将其余部分(CSS文件)延迟加载。

例如:

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

请参见:优化CSS交付


10
您不应该把东西放在 body 元素之外。那篇谷歌文章并未建议任何人这样做。 - ChaseMoskal
2
我担心谷歌页面实际上只是确切地说了那个。 - 10us
8
这个页面似乎曾经推荐过这样的做法,但现在已不再推荐了(现在有一些使用 JavaScript 进行动态加载的方法)。德语版本并未更新,仍包含旧的代码示例。 - bodo
1
“element noscript” 必须在 RFC 中位于 “element html” 和 “element body” 内部。 - Bruno
如果在安全方面使用CSP,您可能不希望在HTML文件中使用CSS。 - Charles L.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接