![HTML5 Mastery系列图片](https://i-blog.csdnimg.cn/blog_migrate/4e2cf302d49f239378029f90f1248639.png)
HTML5最重要的概念之一是统一解析模型。 在HTML规范的早期版本中,实现者有很多自由。 基本上可以选择如何处理某些情况。 造成差异的原因是跨多个浏览器对许多网站进行不同解释的最重要原因之一。 使用HTML5,错误处理已被详细指定,没有任何解释空间。
在“ HTML5精通”系列的第一篇文章中,我们将了解标准中指定的错误处理算法。 我们将看到,其中一些潜在错误实际上是公认的行为,使它们在流行的网站中可用。 本文的主要部分将讨论范围界定规则,该规则涵盖了大多数有经验的行为,因为它们触发了某些算法。 我们从显示隐式结束标记的实际示例开始。
实际例子
标准化HTML5解析器最常用的两个功能是自动构造有效的文档结构和插入隐式结束标记。 我们从后者开始。 演示此功能的一个很好的例子是构建简单列表。 以下代码片段显示了一个包含三个项目的未排序列表。
<ul>
<li>First item
<li>Second item
<li>Third item
</ul>
即使我们省略了结束标记( </li>
),页面也会显示正确的内容。 仅当从给定源正确构造了DOM树时,才可能进行正确的呈现。 DOM树是树层次结构中DOM节点的表示。 DOM节点可以是元素,注释,文本或其他构造,这在本系列的其他部分中都有介绍。
DOM树层次结构始于所谓的根,并显示根的子节点。 根是树的第一个节点。 它没有父元素。 有些节点(例如元素)可以自己拥有子节点。 该树为我们提供了有关实际构建的DOM的信息,而源代码仅提出了一种构建方法。
HTML5解析器可确保在添加新列表项之前插入省略的结束标签。 这符合我们的直觉。 自然,我们认为给定的列表必须包含三个项目。 在HTML5之前,我们实际上可以最终得到一个包含文本的项目和另一个包含文本的项目以及另一个包含文本的项目。
在浏览器中,我们看到以下渲染(左侧)。 我们还可以检查DOM树以检查解析器是否正确处理了方案(右侧)。
![渲染和构造树](https://i-blog.csdnimg.cn/blog_migrate/927edddce70a098a4b286b7616f47cfc.png)
即使已使用Opera(此处为版本31)制作了上述屏幕截图,但该行为与HTML5标准中指定的浏览器无关。
通过查看一些非常受欢迎的网站的源代码,我们可能会发现一些奇怪之处。 例如, 由Google显示的错误页面包含以下标记。
<!DOCTYPE html>
<html lang=en>
<meta charset=utf-8>
<meta name=viewport content="initial-scale=1, minimum-scale=1, width=device-width">
<title>Error 404 (Not Found)!!1</title>
<style>/* ... */</style>
<a href=//www.google.com/><span id=logo aria-label=Google></span></a>
<p><b>404.</b> <ins>That’s an error.</ins>
<p>The requested URL <code>/error</code> was not found on this server. <ins>That’s all we know.</ins>
即使未指定<head>
或<body>
元素,也将构造这些元素。 段落中也隐含了结束标记。 显然,段落的处理类似于列表项。 它们不会嵌套-至少当由HTML5解析器从源构造时才嵌套。
因此,浏览器在右侧生成树,该树将在左侧渲染布局。
![Google错误HTML解析器](https://i-blog.csdnimg.cn/blog_migrate/04f22876af3ce558ecea2d882d5ea185.png)
前面的代码中最重要的几行之一是正确HTML5文档类型的声明。 否则,我们可能最终会进入怪癖模式,就跨浏览器开发而言,该模式本质上等同于未定义的行为。
暗示的结束标签
我们在上一节中看到的行为依赖于隐式结束标记的生成。 当当前节点是以下元素之一时,生成隐式结束标签的机制通过关闭当前节点来工作:
-
<dd>
或<dt>
或<li>
-
<option>
或<optgroup>
-
<rp>
或<rt>
-
<p>
我们认识到,所有这些标签确实有意义。 嵌套的段落定义不明确。 类似地嵌套列表或选项。 它们仅在另一个容器中有意义。
具有隐式结束标签的元素与自闭合元素不同。 在HTML标准中,有些元素是自动关闭的,例如<source>
, <img>
或<input>
。 即使它们是元素,也不应该生孩子。 解析器立即关闭它们。 XML表示这些元素时带有斜杠,而HTML则鼓励省略斜杠。
HTML范围
在许多情况下,应用范围界定。 原则上,一旦HTML5解析器在树构造过程中遇到某些元素,它就会检查该元素是否在某个范围内。 在这种情况下,可能会采取进一步的措施。 否则,通常会忽略当前元素。
确定某个元素是否在给定范围内的过程始于查看当前元素。 如果元素是范围的宿主,那么我们在其范围内。 如果元素在范围指定的元素的特殊子集中,则我们不在范围内。 否则,我们将在当前元素的父元素上继续搜索。
元素的子集可以分为五组。 每个范围选择这些组之一来指定排除元素。 这五个组的名称为:
- 一般
- 项目清单
- 纽扣
- 表
- 选择
列表项和按钮组还包含常规组的所有元素。 该表组仅包含<html>
和表元素本身。 选择组包括除<optgroup>
和<option>
之外的所有元素。
作用域示例
选择组可用于很好地说明通过使用这些作用域规则将得到的结果。 例如,如果我们关闭选择元素,则会检查选择组中是否有<select>
元素。 如果不是这种情况,那么结束标记将被忽略。 否则,我们将关闭所有元素,直到我们实际上关闭了选择节点。
让我们看一些代码。 将生成什么树?
<select><optgroup><option>First</select>
实际上,这太容易了。 我们的直觉告诉我们</select>
也会同时关闭选项和选项组。 这是对的。 实际上,我们仅限于在select元素内使用option和option组元素。 这是由解析器监督的。 那现在呢?
<p><optgroup><option>First</select>
好吧,这里有两个主要区别。 首先,我们首先没有输入选择元素。 因此, <optgroup>
和<option>
不会受到解析器的约束。 他们还可以采用任意元素。 其次,关闭select元素将被忽略。 此行为的根源在于所应用的作用域规则。
现在让我们考虑一些可能影响标记设计的行为。 以下代码段的构建后的DOM树是什么样的?
I am from
Germany.
没有比这更容易的了吗? 好吧,不是那么快。 乍一看,标记似乎合法。 毕竟,它只是在语义上声明内部的地址,对吗? 不幸的是没有。 <address>
元素也被视为一个块,如一个段落。 此块与CSS无关,因此我们不能通过使用其他display
声明来更改行为。
我们已经看到构造的DOM有所作为(右)。 渲染紧随其后(左侧)。
![范围地址段落](https://i-blog.csdnimg.cn/blog_migrate/f6608f601eb5d6887a7c370dd6a1ffc3.png)
此行为适用于相当多的元素。 规范内容如下:
一个开始标签,其标签名称是以下之一:“地址”,“文章”,“旁边”,“块引号”,“中心”,“详细信息”,“目录”,“ div”,“ dl”,“字段集”, “ figcaption”,“ figure”,“ footer”,“ header”,“ hgroup”,“ menu”,“ nav”,“ ol”,“ p”,“ section”,“ summary”,“ ul” […]
所有这些元素将检查按钮组中是否有段落元素。 在这种情况下,该段将被关闭。
在许多其他地方,上下文/祖先元素实际上很重要。 这一切都使得HTML代码片段非常不本地化。 但是,现在,我们将讨论另一个错误处理主题。
重新格式化和表格
让我们从一个简单的问题开始。 以下代码的DOM树是什么样的?
<p>1<b>2<i>3</b>4</i>5</p>
在3
之前确定结果树肯定不是很困难,但是问题开始了。 对于接下来将要发生的事情,没有很好的论据。 这就是某些浏览器供应商决定引入一种算法的原因,该算法描述了重新格式化的工作方式。
首先,封闭的粗体标签表示所有包含的标签的结尾。 在我们的示例中,这会影响斜体。 但是,由于我们没有关闭斜体标签,因此我们必须对其进行特殊处理。 在关闭所有内部标签之后,我们需要为隐式关闭的格式标签打开新的标签。 格式标签是与元素相对应的普通标签,它对包含的文本格式具有(历史的)影响。
下图显示了结果。 左侧的树是直到3的构造,而右侧的树则显示了代码段后的完整图片。
![重新格式化DOM树](https://i-blog.csdnimg.cn/blog_migrate/10d78bc4276d9c9b8eea28301ed09188.png)
在CSS时代,格式化元素的重建可以认为已经过时了,但绝不是过时的。 当元素关闭时,它不是直接触发的,而是在插入新文本时才触发的。
另一个有趣的主题是格式与表格元素的连接。 表中的错误处理非常奇怪。 似乎没有人凭直觉就能做到这一点。 从历史上看,它是由许多具有不同哲学的供应商开发的。
让我们再考虑一个例子。 DOM树如何查找以下代码段?
<table><b><tr><td>aaa</td></tr>bbb</table>ccc
<table>
仅允许表节元素。 正如之前在核心HTML元素(例如<head>
或<body>
)中看到的那样,解析器通常会处理此问题。 例如,如果将行直接附加到表中,则会自动插入<tbody>
节来处理该行。
因此,自然的做法是在<body>
粗体格式元素。 但是,由于我们为文本指定了粗体格式,因此我们仍然需要对任何文本(表格外部)使用它。 因此,第一步是继续产生任何带有一些(正常)文本的表(在插入的<b>
元素之后)。
关闭该行后,我们会遇到更多文本。 该文本在表格中,但尚未放置在单元格中。 因此,必须像粗体元素一样将其附加在表格之前。 此处,粗体格式仍处于活动状态,即,文本不会以独立的方式附加,而是需要包装在<b>
标记中。
最后,我们在表外有一些文字。 我们可以正确地猜测出该文本必须在DOM树中的表之后,但是关键的问题是:是否应该格式化? 唯一正确的答案是“否”,它不应该。 为什么? 原因是我们从未关闭过粗体标签。 由于粗体标签已从桌子转移到身体,因此我们仍然没有关闭它。
![表格式DOM树](https://cms-assets.tutsplus.com/uploads%2Fusers%2F659%2Fposts%2F24840%2Fimage-1442219218731.png)
前一个示例中的标记不能被认为是可读,直观或根本不需要的。 我们已经看到的行为是工作中的错误恢复模型,不需要做任何事情。 我选择了该示例来说明嵌套不兼容标签的问题(并由解析器显示解决方案)。 大多数情况下,此类问题是由于复制/粘贴或版本控制合并错误而发生的。
结论
了解HTML5解析器内部非常重要。 这些知识导致正确的缩小规则,该规则可以节省许多字节和一些解析时间。 现在,我们对HTML解析器引起的错误处理有了基本的了解。
范围规则在HTML5解析过程中始终很明显。 我们处理一个极其有状态的过程,该过程不会将元素视为相等或未知。 相反,我们有大量的特殊行为,这些行为高度依赖于当前范围,该范围由所考虑的元素定义。
我们还看到,猜测正确的树并不总是像应该的那样直观。 一般而言,我们应尽量避免出现此类问题区域。
翻译自: https://code.tutsplus.com/tutorials/html5-mastery-scoping-rules--cms-24840