【问题标题】:Nested <p> tag auto-closing/opening嵌套 <p> 标签自动关闭/打开
【发布时间】:2017-04-13 15:08:14
【问题描述】:

我在嵌套的 &lt;p&gt; 标记周围看到了一些奇怪的行为。测试用例见this

给定:

<p>
  <p>
    <p>
      <p>
        <p>
          <p>
          </p>
        </p>
      </p>
    </p>
  </p>
</p>

在 Chrome 中,这会导致

<p>
  </p><p>
    </p><p>
      </p><p>
        </p><p>
          </p><p>
          </p>
        <p></p>
      <p></p>
    <p></p>
  <p></p>
<p></p>

也就是说,它关闭开始标签并打开结束标签。我(当然)听说过“自动关闭标签”;我从来没有听说过“自开标签”。

IE11 以不同的方式(可以说,甚至更错误):

<p>
  <p>
    <p>
      <p>
        <p>
          <p>
          </p>
        <p></p>
      <p></p>
    <p></p>
  <p></p>
<p></p>

所以它不会自动关闭开始标签,但会自动打开关闭标签,导致 DOM 树不平衡。

无论如何,我很好奇解决这个问题的正确途径是什么;我应该在 Chrome 和 IE 错误跟踪器上打开问题吗?我不是特别精通 W3C 规范,我会去哪里尝试找到“正确”的行为(我不知道除了 &lt;p&gt; 之外的任何标签都表现出这种行为,尽管我没有做过广泛的测试)?

不管怎样,我意识到嵌套&lt;p&gt; 标签是无效的;这是我正在与他们一起解决的第三方库的结果,我只是发现这是一种奇怪的行为)。

编辑:我对 IE 的看法是错误的:请参阅 https://jsbin.com/ripaxe/5/edit?html,js,output。原来innerHTML 依赖于浏览器。没想到。

【问题讨论】:

    标签: html


    【解决方案1】:

    这不是错误。正如您所说,&lt;p&gt; 元素不能嵌套在其他 &lt;p&gt; 元素中。

    Chrome 正在尝试通过为您关闭 &lt;p&gt; 标记来修复您的代码,从而生成此标记。我建议使用您正在使用的第三方库提出错误报告,因为这不是特定于浏览器的问题。

    【讨论】:

    • 好吧,我明白了。这是无效的 HTML。对我来说奇怪的是a)它也是自动打开标签和b)浏览器之间的行为不一致(在IE11的情况下,导致DOM树不平衡)。也许规范中未定义行为?我不知道,但似乎并非所有标签(特别是自打开标签)都会发生这种行为。
    • Chrome 将&lt;p&gt;&lt;p&gt; 视为&lt;p&gt;&lt;/p&gt;&lt;p&gt;。它还将独立的&lt;/p&gt; 视为&lt;p&gt;&lt;/p&gt;,因此您的6 个嵌套&lt;p&gt; 元素变成11 个&lt;p&gt; 非嵌套元素。这是 Chrome 尝试为您修复代码的所有部分。 IE 也尝试为您修复代码,但它以不同的方式(如您所知)。不过,这里的责任在于第三方库,而不是浏览器。浏览器很容易拒绝呈现页面并给出关于无效 HTML 的错误,但它会尝试以自己的方式呈现它。
    • @Turner Hayes:IE11 的行为真的会导致树不平衡吗?您是否验证了 p 元素实际上是嵌套的,而不是 IE 根本不显示结束标记?
    • "浏览器很容易拒绝渲染页面并给出关于无效 HTML 的错误" 您可能正在考虑 XHTML,其中 需要 浏览器拒绝渲染页面格式不正确或无效。
    【解决方案2】:

    您的测试用例使用 innerHTML 来显示标记的序列化。不出所料,IE 的处理方式与其他浏览器不同,但浏览器对您的标记的表示都不是错误的本身

    Chrome(和 Firefox)会插入明确的 &lt;/p&gt; 结束标签,以准确显示每个 &lt;p&gt; 开始标签的终止位置。每个开始标签在下一个开始标签之前立即终止(最后一个除外,它由其结束标签终止)。请注意,空格包含在每一对中。

    但是不需要显式的结束标签,并且 IE 只是选择不插入结束标签来匹配任何开始标签。这并不意味着存在任何嵌套——所有 p 元素仍然是兄弟元素,您可以通过以下事实来验证这一点:document.querySelector('p p') 返回 null 并且 document.querySelector('p:nth-child(11):last-child') 返回最后一个表示的元素&lt;/p&gt; 所有浏览器中的结束标记。

    当然,原始标记中的结束标记会被保留,但除了第一个结束标记之外的所有结束标记都与它们自己的开始标记匹配(这次 没有 包含空格)的原因是在Why does a stray </p> end tag generate an empty paragraph? 中进行了描述——简而言之,它是由 HTML5 指定的,以便与旧版浏览器行为保持一致。

    p 元素的结束标记是可选的,这也是为什么这两种表示形式同样有效(实际上在功能上等效)HTML 片段的原因。因此,IE 所做的事情并没有错,但它确实让依赖于 innerHTML 属性的作者感到头疼,因为它做事不同。

    但这就是为什么你不应该依赖innerHTML。

    【讨论】:

    • 我意识到它最终不会因为自动关闭而被嵌套,即使源标记试图这样做。不过,您添加的链接很有用 - 它至少解释了自动打开。这是&lt;p&gt; 独有的吗?如果我理解正确,您是说 IE 最终具有与 Chrome 相同的有效 DOM 结构,只是它的innerHTML 没有显示它?这似乎是对的;我改用了XMLSerializer,这棵树在 IE 中看起来也很正确。谢谢,我没有意识到innerHTML 不规范。
    • @Turner Hayes:是的,它是 p 元素独有的。 br 元素存在类似的行为,但 br 是一个 void 元素,这意味着它首先不能有结束标签,所以我认为它不重要。是的,片段

      (两个开始标签)和

      (两对开始和结束标签)是等价的,并不是因为浏览器处理的方式但因为 HTML 语法表明它们是。
    猜你喜欢
    • 1970-01-01
    • 2019-05-16
    • 1970-01-01
    • 1970-01-01
    • 2018-04-03
    • 1970-01-01
    • 1970-01-01
    • 2011-04-09
    • 2021-04-03
    相关资源
    最近更新 更多