Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. HTML5
Code

精通HTML5: 作用域规则.

by
Difficulty:IntermediateLength:MediumLanguages:
This post is part of a series called HTML5 Mastery Class.
HTML5 Mastery: Encoding

Chinese (Simplified) (中文(简体)) translation by Feng Huang (you can also view the original English article)

HTML5 Mastery series image

一个非常重要的概念是HTML5是一个标准的解析模型. 早期的HTML规范,实现起来自由度很大. 一种基本配置能够对应处理一种特定环境. 这就导致许多的网站在处理跨浏览器问题上需要提供多种方案. 在HTML5中,错误处理非常的详细, 不需要再进行专门处理?

在精通HTML5系列的第一篇文章. 我们来学习一下标准的错误处理方法. 我们将看到在现在流行的网站上一些潜在的错误实际上是可以接受的行为. 这篇文章的主要部分讨论了作用域规则.   覆盖了当触发算法行为时的很多经验. 我们开始通过部分样子来展示闭合标签的实现.

真实案例

标准HTML5分析器的两个最常用的功能文档结构的自动构建和提示插入结束标记. 我们从后者开始介绍. 一个真实例子. 构建一个简单的说明列表. 下列代码片段展示未排序的三个列表元素.

即使我们省略的</li>关闭标签页面依然显示正确. 唯一正确的渲染方式是从给定的源代码构建DOM树. DOM树是DOM节点的树形层次结构描述. 一个DOM可以是一个html元素,一段注释,文本,或其他结构.  这回在这系列其它部分来介绍.

DOM树结构开始的元素被称为root并且显示root的子节点. root就是树形结构的第一个节点. 这是一个没有父元素的元素. 一些节点,例如一些元素,可以有属于自己的子节点. 树形结构给我们了关于实际DOM的结构信息. 而代码只是提出构建.

HTML5分析解析器确保在新列表元素前插入漏掉的结束标签. 这样符合我们的思维习惯. 我当然认为列表项里有三个元素. 在HTML5之前的版本. 实际上有可能会一个单独的元素中包含文本和其另外包含文本和其它元素的元素.

在浏览器中我们看到下面的的渲染效果.(左侧) 我们也可以通过检查DOM树验证解析处理是否正确.(右侧)

Rendering and constructed tree

甚至通过Opera浏览器(这里的版本是31)来截屏.  因为它的行为独立支持HTML5标准.

在查看很多流行网站的源代码我们会发现一些奇怪的事. 一些包含下列标记的实例错误页面显示在Google上.

即使没有指定<head>或者<body>元素的页面也可以正常显示.. 尽管段落有关闭标签. 显然段落被视为和列表项一样处理. 至少当源代码有HTML5解析器创建的时候. 他们不会被嵌套.

因此浏览器生成的树在右侧,渲染页面布局在左侧.

Google Error HTML Parser

在前面的代码最重要之一行就是正确的 HTML5 文档类型的声明。 否则我们可能变成在混合模式,也就是相当于未定义的行为的跨浏览器的开发。

隐含的结束标签.

我们看到在前一节的行为依赖于生成的隐含的结束标签。 当前节点是以下内容之一时生成隐含的结束标记的机制是通过关闭当前节点实现:

  • <dd> <dt><li>
  • <option> <optgroup>
  • <rp><rt>
  • <p>

我们认识到,这个规则真的影响所以这些标签。 一个嵌套的段落是不明确的。 同样的嵌套的列表或可选项。 他们只有在其它的容器内才有效.

一个隐藏结束标记的元素和本身包含结束标记的元素是不一样的. 在HTML标准元素中.<source>,<img><input>这些元素本身自带结束标记. 当然所有这些元素他们都不支持包含子元素. 所以解析器可以立即帮他们加上关闭标签. 而 XML 表示这些元素与一个尾随的斜杠,HTML 鼓励不使用斜线。

HTML 作用域

作用域有很多的应用场景. 原则上,一旦 HTML5 分析器用一些元素构建树形结构时,看起来所有元素是在一定范围内的。 如果是这样,下一步有可能会做这些动作。 否则通常忽略当前元素。

确定某元素是否作在当前的作用域内以当前元素为参照. 如果目标元素和当前元素有相同的父元素. 他们就在一个作用域内. 如果目标元素是当前元素作用域内元素的子元素,就不在作用域内. 否则我们继续搜索当前元素的父元素.

元素的子集可以分为5部分. 每个作用域如果包含在其中一组就不会包含在另外几组中. 这五组名称为:

  1. General
  2. List item
  3. Button
  4. Table
  5. Select

list item和button组同时包含所有General组的元素. table组只包含<html> 和 table元素自己. 选择组包括除 <optgroup><option>组外的所有元素。

作用域例子

用select组来为例让我们更好了理解使用作用域规则. 例如在一个包含<select>元素的select组中关闭select元素, 如果没有这一规则,则关闭标签被忽略. 否则我们关闭所有元素直到关闭select节点.

看上去像这样的代码: 会生成什么样的树形?

实际上这很简单. 我们直觉告诉我们应该用</select>来关闭option组为好. 这样就是正确的. 我们实际是限于在select元素中使用option和option组. 这些都在解析器的监督下. 现在的情况是什么样呢?

这里主要有两点不同的地方. 首先在开始的地方我们没有输入select元素. 所以<optgroup><option>就不受解析器约束. 他们可以是任意元素。 第二,闭合的select元素可以省略. 原来的行为不适应新的作用域规则.

让我们现在考虑一些可能会影响您的标记设计的行为。 下列代码段那些看起来能成功构建DOM树.

没有比这简单一些的,有么? 好吧,不是那么快。 标记可能看起来乍一看很有规律。 毕竟,它只是语义上在里面定义一个地址,是吧? 可惜不是。 <address>元素也被认为是一个块,如一个段落。 此块与 CSS无关,所以我们不能通过使用不同的display声明更改行为。

我们已经看到构造的不同的DOM  (右图)。 渲染只是遵循 (左侧)。

Scope Address Paragraph

此行为适用于很多元素。 规则如下:

A 如果开始的标记的标记名称是下列中的一个:"address"、"article"、"aside"、"blockquote"、"center"、"details"、"dir"、"div"、"dl"、"fieldset""、"figcaption"、"figure"、"footer"、"header"、"hgroup"、"menu"、"nav"、"ol"、"p"、"section"、"summary"、"ul"[......]

所有这些元素将检查是否有一个段落元素在button组中。 如果符合这个条件,这一段将会封闭。

在很多其它地方的上下文上父元素是非常重要的. 这一切都使 HTML 片段高于non-local。 然而,现在我们将看另一错误处理主题。

重新格式化和表

让我们从一个简单的问题开始。 下列代码生成什么样的DOM树.

当然不是很难画出树形结构, 直到 3的位置, 问题来了。 没有真正很好的理由,接下来应该发生什么。 这是一些浏览器供应商决定引入一种算法,描述了如何重新格式化工作的原因。

第一,结束粗体标记意味着为所有的标记结束。 在我们的例子中,这会影响斜体。 但由于我们没有关闭斜体标记,我们必须对它特殊处理。 当已经关闭内部标记后,我们需要打开新的隐式封闭格式标记。 格式化标签是一个对应于一个元素有(historical)consequences 的包含文本的格式正常的标签,。

下图显示正确的结果。 在左边的树是直到 3之前的结构,而右侧树说明了解析完整代码后的结构。

Reformatting DOM Tree

在认为CSS 的格式设置元素重建已经过时的时代也不会过时。 当关闭元素他不会直接被触发,但当插入新文本会。

另一个有趣的话题是连接的表元素的格式。 表中的错误处理是很奇怪的。 似乎没有人直观地理解它。 从历史上看,它是根据不同供应商开发不同的规则。

让我们再考虑一个例子。 下面的代码段会生成什么样的DOM树?

<table> 里只允许存在table类元素。 正如前面看到核心 HTML 元素 (如 <head><body>),解析器通常会很注意这些。 例如,如果直接向表添加一行,<tbody>节是自动插入行的照顾。

因此自然不过的是 给<body>追加粗体格式。 但是,由于我们指定文本的加粗格式,我们仍然需要对任何文本 (表外部文本)加粗。 因此第一步是插入<b>元素后继续生成table,和一些 (普通) 的文本。

关闭行后,我们会遇到更多的文本。 此文本是在table,但它已不在一个单元格中。 因此,类似粗体元素要在table之前追加。 在这里加粗格式是仍处于活动状态,即不会单独添加,但需要包装在 <b>标记中追加文本。

最后,我们还有一些在table外的文本。 我们可以猜测的到哦这个文本在DOM树中table的的后面,但关键的问题是: 它被格式化了吗? 唯一正确的答案是不,它没被格式化。 为什么? 原因是我们永远没办法关闭粗体标记。 因为粗体标记已经从table转移到body里,我们仍然没有关闭它。

Table Formatting DOM Tree

在前一个例子中的标记根本不能被认为是可读的,直观的或是想要的。 我们看到行为是一个错误回复模式在工作. 没有 什么是按要求的. 我选择的例子来说明问题 (或者用解析器显示的解决方案) 的嵌套不兼容的标记。 大多数情况下这类错误发生复制/粘贴或版本控制合并时。

结论

了解 HTML5 解析器内部机制是重要的。 这方面的知识,导致右缩小规则,可以节省很多字节和一些解析的时间。 我们现在对HTML 解析器对误差的处理有了一个基本的了解。

作用域规则始终表现在 HTML5 的解析过程中。 我们处理的是一种极端的状态,不需要的相等的或未知的元素。 相反,我们有一大堆的是高度依赖于当前的范围,经过深思熟虑的元素所定义的特殊行为。

我们也看到右边的树不是总是像我们觉得应该的样子。 在一般情况下我们应尽量避免出现此类问题的地方。

引用

Envato qr branded
关注我们的公众号
Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.