【问题标题】:How is code *between* the end of the HEAD tag and before the BODY tag processed?HEAD 标记的结尾和 BODY 标记之前的代码是如何处理的?
【发布时间】:2017-01-26 17:23:56
【问题描述】:

我已阅读 that it is bad 来执行此操作,并且超出了规范,但我遇到了一个间歇性错误,可能与此有关。只是想知道普遍的共识是“用凝固汽油弹烧掉那个代码”还是“在这些有限的条件下它可以工作”。

我发现,在我们维护的一个非常复杂的代码库中,<script> 标签既可以从外部源(javascript 和 jquery)加载,也可以在</head> 之后和<body> 之前的内联脚本加载。大部分是表单完全加载后需要加载的代码。

在我开始进行更改以将代码合并到 Head 标记的底部之前,我想了解运行此代码的客户端 现在发生了什么(目标是不会破坏当前的用户体验)。这些脚本是在页面渲染之前加载还是之后加载?这个原本不应该存在的无人区代码的实际状态是什么?

谢谢!

【问题讨论】:

  • 浏览器尽最大努力从这样的损坏代码中理解。

标签: javascript jquery html


【解决方案1】:

从根本上说,这是无效标记和解析错误,浏览器必须从中恢复。所以我会在你的目标浏览器中测试它,看看它们做了什么。

理论上:在结束</head> 标记之后和开始<body> 标记之前,解析器在“'after head' insertion mode”中。我在下面列出了规则,但感谢your comment,我认为相关的规则是:

  • 标签名称为以下之一的开始标签:“base”、“basefont”、“bgsound”、“link”、“meta”、“noframes”、“script”、“style”、“template”、“标题”
    • 解析错误。
    • 将头元素指针指向的节点推入打开元素的堆栈。
    • 使用“in head”插入模式的规则处理令牌。
    • 从打开的元素堆栈中删除头元素指针指向的节点。 (此时它可能不是当前节点。)
    • 此时头元素指针不能为空。

这告诉我们:

  1. 这是一个解析错误,请参阅我的开头段落。 :-)
  2. 规范似乎告诉浏览器供应商将脚本视为位于head 的末尾。

完整规则:

当用户代理要应用“后头”插入模式的规则时,用户代理必须按如下方式处理令牌:

  • 一个字符标记,它是 U+0009 CHARACTER TABULATION、"LF" (U+000A)、"FF" (U+000C)、"CR" (U+000D) 或 U+0020 SPACE 之一

    • 插入字符。
  • 评论标记

    • 插入评论。
  • 一个 DOCTYPE 令牌

    • 解析错误。忽略令牌。
  • 标签名称为“html”的开始标签

    • 使用“in body”插入模式的规则处理令牌。
  • 标签名称为“body”的开始标签

    • 为令牌插入 HTML 元素。
    • 将 frameset-ok 标志设置为“not ok”。
    • 将插入模式切换为“in body”。
  • 标签名称为“frameset”的起始标签

    • 为令牌插入 HTML 元素。
    • 将插入模式切换为“in frameset”。
  • 标签名称为以下之一的开始标签:“base”、“basefont”、“bgsound”、“link”、“meta”、“noframes”、“script”、“style”、“template”、“标题”

    • 解析错误。
    • 将头元素指针指向的节点推入打开元素的堆栈。
    • 使用“in head”插入模式的规则处理令牌。
    • 从打开的元素堆栈中删除头元素指针指向的节点。 (此时它可能不是当前节点。)
    • 此时头元素指针不能为空。
  • 标签名称为“模板”的结束标签

    • 使用“in head”插入模式的规则处理令牌。
  • 标签名称为以下之一的结束标签:“body”、“html”、“br”

    • 按照下面“任何其他”条目中的说明进行操作。
  • 标签名称为“head”的开始标签

  • 任何其他结束标记

    • 解析错误。忽略令牌。
  • 其他的

    • 为没有属性的“body”开始标记标记插入 HTML 元素。
    • 将插入模式切换为“in body”。
    • 重新处理当前令牌。

【讨论】:

  • 我明白为什么浏览器开发人员在阅读本规范时可能会不同意! “标签名称为以下之一的开始标签:...,“脚本”,...解析错误。将头元素指针指向的节点推入打开元素的堆栈。使用规则处理令牌“in head”插入模式。从打开的元素堆栈中删除头元素指针指向的节点。(此时可能不是当前节点。)此时头元素指针不能为空。这看起来像是重新打开了 head 元素,将脚本推入其中,然后再次关闭了 head?
  • (对不起,我忘了 cmets 不保留换行符)
  • @Dan:那么我的结论是无效的,因为我错过了这条规则!已修复,抱歉。
  • 很难选择哪个是“正确”答案(接受的答案),因为我们最终都到达了同一个目的地。我只选择了@BoltClock,因为他的阅读时间较短,可以深入了解我需要了解的内容。
  • @Dan:在我看来,就其价值而言,您做出了正确的决定。 (不像你需要我的许可或祝福,但一样……)
【解决方案2】:

出现在</head> 结束标记和<body> 开始标记之间的内容被插入到刚刚超过<body> 开始标记,除非它是不属于正文的元素,在这种情况下,它将被插入到头尾。

某些元素,例如script,可能出现在头部或主体中;该位置的脚本元素将被插入到头部的末尾,除非浏览器已经处于“in body”插入模式,在这种情况下它们将被放置在 body 中。 p>

有关详细信息,请参阅 W3C HTML 的 8.2.5.4.4 The "in head" insertion mode8.2.5.4.6 The "after head" insertion mode8.2.5.4.7 The "in body" insertion mode 部分。请注意,由于历史原因、错误或故意违反规范的决定,不保证实现遵循规范,不应依赖此行为。

【讨论】:

  • 因此,当前遵循规范的任何浏览器都会将这些<script> 块视为出现在<head> 块之内和末尾处。因此,1) 将这些脚本移到头部应该不会造成任何问题,并且 2) 这些不合适的脚本目前可能不会造成任何问题?
  • @Dan:如果他们还没有遵循将出现在正文中的元素,是的。我还没有听说过任何直接拒绝运行它们或无序运行它们的实现,但我仍然不会依赖它。如果可以,请修复标记错误,并经常测试。
  • 感谢规范的链接。有趣的阅​​读,虽然有点难以理解,但任何试图理解解析 HTML 时要遵循的规则的文档本质上都是具有挑战性的。
  • @Dan:幸好我们不是浏览器开发者。
  • 很好的答案!简洁明了。
猜你喜欢
  • 1970-01-01
  • 2015-11-22
  • 2011-02-04
  • 2023-03-31
  • 2011-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多