1. 1 概述
    1. 1.1 本标准的适用范围
    2. 1.2 这是 HTML5 吗?
    3. 1.3 背景
    4. 1.4 受众
    5. 1.5 范围
    6. 1.6 历史
    7. 1.7 设计笔记
      1. 1.7.1 脚本执行的可串行性
      2. 1.7.2 与其他标准的兼容性
      3. 1.7.3 可扩展性
    8. 1.8 HTML 和 XML 语法
    9. 1.9 本标准的结构
      1. 1.9.1 如何阅读本标准
      2. 1.9.2 排版惯例
    10. 1.10 HTML 的简单介绍
      1. 1.10.1 使用 HTML 编写安全应用
      2. 1.10.2 使用脚本 API 时常见的陷阱
      3. 1.10.3 编写 HTML 时如何发现错误:验证器和一致性检查器
    11. 1.11 对页面作者的一致性要求
      1. 1.11.1 表示性的标记
      2. 1.11.2 语法错误
      3. 1.11.3 内容模型和属性值的限制
    12. 1.12 推荐阅读

1 概述

1.1 本标准的适用范围

本标准详细地定义了 Web 平台的很大一部分内容。Web 平台的标准栈中,它相对于其他标准的定位可以总结为:

CSS SVG MathML NPAPI Geo Fetch CSP JPEG GIF PNG THIS SPECIFICATION HTTP TLS MQ DOM Unicode Web IDL MIME URL XML JavaScript Encodings

1.2 这是 HTML5 吗?

This section is non-normative.

简单地说:是的。

详细地说,广义的 "HTML5" 是指一系列的现代 Web 技术。 这些技术中很多都由 WHATWG 开发,本文档就是其中之一。 其他的可以在这里访问: the WHATWG Standards overview

1.3 背景

This section is non-normative.

HTML 是万维网的核心标记语言。最初 HTML 主要设计为在语义级别描述科学文档的语言。 然而它的总体设计使它在接下来的几年中能够适配一些其他类型的文档,甚至包括应用程序。

1.4 受众

This section is non-normative.

本标准是为以下读者提供的:使用了本标准定义的特性的文档和脚本的作者, 用于操作那些使用了本标准定义的特性的页面的工具的实现者, 希望根据本标准的要求确认文档或实现的正确性的个人。

本文档对还没有整体熟悉 Web 技术的读者可能不合适, 因为在有些地方为精确性而省略了具体阐述,为完整性而较为简洁概括。 易懂的教程和编写指南可以为这个话题提供更加温和的介绍。

具体地,为了完整地理解本标准中那些更加技术的部分,对 DOM 基础的熟悉是必要的。 对 Web IDL,HTTP,XML,Unicode,字符编码,JavaScript 和 CSS 的理解在有些地方也有帮助,但并非完全必要。

1.5 范围

This section is non-normative.

本标准只限于为编写可访问的 Web 页面(从静态文档到动态应用) 提供语义级别的标记语言,以及相应的语义级别的脚本 API。

本标准的范围不包括提供具体媒体的自定义呈现机制(尽管 Web 浏览器的默认渲染规则在本标准末尾有所涵盖, 一些挂钩到 CSS 的机制也作为语言的一部分加以提供)。

本标准的范围并非要描述整个操作系统。具体地,硬件配置软件、图像操作工具、 以及用户在高端工作站日常使用的应用程序都在范围之外。 对于应用软件,本标准只针对用户偶尔使用的,或定期使用但在不同地点的, 且 CPU 要求较低的特定应用。这样的应用例如在线购物系统、搜索系统、游戏(尤其是多人在线游戏)、 公开电话簿或地址簿、通信软件(邮件客户端、即时通信客户端、讨论软件), 文档编辑软件等。

1.6 历史

This section is non-normative.

在最初的5年中(1990-1995),HTML经历了若干次修订和扩展。最初由 CERN 主要托管,随后是 IETF。

随着 W3C 的诞生,HTML 的开发再次易主。1995 年第一次扩展 HTML 的尝试(HTML 3.0)以失败告终,随后转变为更加务实的 HTML 3.2,在 1997 年完成。 就在同年很快开始了 HTML4 的开发。

随后一年 W3C 成员决定停止 HTML 的演变,并开始开发基于 XML 的替代品 XHTML。 该 工作首先将 HTML4 重新规划为 XML,也就是著名的 XHTML 1.0。 唯一增加的特性就是新的序列化,该工作在 2000 年完成。 XHTML 1.0 之后,在 XHTML 模块化的口号下 W3C 的主要精力转向让其他工作组更容易地扩展 XHTML。 与此同时,W3C 致力于一门新的、与此前的 HTML 和 XHTML 都不兼容的语言:XHTML2。

大概在 1998 年 HTML 停止演化的时候,浏览器厂商开发的部分 HTML API 被标准化和发布在 DOM Level 1(1998) 和 DOM Level 2 Core,以及 DOM Level 2 HTML(2000年开始2003年完成)中。 在 2004 年发布了一些 DOM Level 3 标准,但是 Level 3 草案尚未全部完成工作组就关闭了。 这些工作也最终不了了之。

2003 年 XForms (一项定位于下一代 Web 表单的技术)的发布 重新激起了对 HTML 演化的兴趣,而不是像从前那样寻求新的替代品。 这时人们发现 XML 作为 Web 技术的部署只局限于全新的技术(比如 RSS 和后来的 Atom), 而不是取代已经部署的技术(比如 HTML)。

概念验证显示,在不要求浏览器实现与现存 HTML Web 页面不兼容的渲染引擎的情况下, 也可能扩展 HTML4 的表单来提供 XForms 1.0 引入的很多特性。 这一概念验证是对 HTML 重新燃起的兴趣产生的第一项成果。 在这早期阶段,虽然本草案已经公开可用且已广泛征求建议,该标准只在 Opera Software 版权下发布。

应该重新开启 HTML 演化的想法在 W3C 工作组得到了测试。 Mozilla 和 Opera 共同向 W3C 工作组提交了提议,包括 HTML5 工作背后的一些原则(见下文),以及前述的只涉及表单特性的早期草案。 该提议因为与此前选择的 Web 演化方向冲突而被拒绝, W3C 职员和会员投票支持继续开发基于 XML 的替代品。

此后 Apple,Mozilla 和 Opera 共同声明他们将继续在 WHATWG(一个新的组织)团体下投入工作。 他们为此创建了一个公开的邮件列表,草案也移交到了 WHATWG 网站。随后版权也修改为这三家共同拥有, 同时允许该标准的重用。

WHATWG 基于若干核心原则,具体地:技术需要向后兼容,标准和实现需要相符(即使这意味着更改标准而不是实现), 标准需要足够详细来使得一个实现在不需对其他实现进行逆向工程的情况下,就能可达到完全的互操作性。

其中后一个原则,要求 HTML5 标准的范围应包括先前在 HTML4,XHTML1,和 DOM2 HTML 这三篇独立的文档中标准化的内容。 同时意味着相比于此前的考虑,需要显著地引入更多的细节。

2006 年,W3C 暗示了参与 HTML5 开发的兴趣,并于 2007 年组建了工作组来与 WHATWG 共同开发 HTML5 标准。 Apple,Mozilla,和 Opera 允许 W3C 在 W3C 版权下发布该标准, 只要保留一版 WHATWG 网站的那份较少限制的许可协议。

数年中各方一同工作,然而在 2011 年,这些工作组最终发现他们有着不同的目标: W3C 希望发布一个"完成的" HTML5 版本,而 WHATWG 希望持续地维护一个 HTML Living Standard, 持续地维护该标准而不是锁定在一个带着已知问题的状态, 同时按照需求增加新的特性来发展整个平台。

从此 WHATWG 一直在(与其他组织一同)开发该标准, W3C 则复制 WHATWG 的修复工作到他们所在的文档分支(也有其他的一些改动)。

1.7 设计笔记

This section is non-normative.

必须承认 HTML 的很多方面乍一看毫无意义或者不太一致。

HTML,它的 DOM API,以及很多其他的支持技术是由互不相识的有着不同目的的人,经数十年开发完成。

因此特性的出现有着不同的来源,也未经专门的一致的方式设计。 而且由于 Web 独有的特点,实现的 Bug 常常会变成事实上的惯例,以及现在合法的、标准的行为。 因为编写的内容常常会无意地依赖于这些未能及时修复的实现。

尽管这样,人们还是为坚持某些设计目标而付出努力。在接下来的几个小节中描述了这些努力。

1.7.1 脚本执行的可串行性

This section is non-normative.

为了避免让 Web 作者处理多线程的复杂性,HTML 和 DOM API 的设计使得脚本无法检测同时运行的其他脚本。 甚至在使用 workers 时,设计意图中实现的行为可以被认为是 在所有 浏览环境 中串行地执行所有脚本。

1.7.2 与其他标准的兼容性

This section is non-normative.

本标准和多种多样的其他有相互影响和依赖。很不幸在某些情况下,相互冲突的需求使得本标准违反了其他标准的要求。 当这种情况发生时,每一项冲突都会标记为 "willful violation",而且会说明该冲突的原因。

1.7.3 可扩展性

This section is non-normative.

HTML 有广泛的可扩展性机制,可用来安全地添加语义:

1.8 HTML 和 XML 语法

This section is non-normative.

本标准定义了一个描述文档和应用的抽象语言,以及一些 API 来与使用该语言的资源的内存表示进行交互。

这一内存表示又称为 "DOM HTML",或简称为 "DOM"。

对于传输使用了该抽象语言的资源,有很多不同的具体语法。本标准中定义了其中两种。

第一个这样的具体语法是 HTML 语法。这是对多数作者推荐的格式,它与多数遗留的 Web 浏览器相兼容。 如果一个文档以text/html MIME type进行传输, 然后它将会被 Web 浏览器作为 HTML 文档处理。 本标准定义了最新的 HTML 语法,简单地称为 "HTML"。

第二个具体的语法是 XML。当一篇文档以XML MIME type(比如application/xhtml+xml) 传输时,它将会被 Web 浏览器当做 XML 文档处理,被 XML 处理器解析。 作者需要注意 XML 和 HTML 的处理存在差别;具体地,即使很小的语法错误都将阻止 XML 文档的完整渲染, 然而它们在 HTML 语法中将会被忽略。

给 HTML 用的 XML 语法此前被称为 "XHTML",但本标准不适用该术语 (原因之一是 MathML 和 SVG 的 HTML 语法中未使用该术语)。

DOM,HTML 语法,XML 语法不能用来表示同样的内容。 例如 HTML 语法不能表示命名空间,但 DOM 和 XML 语法却支持。 类似地,HTML 语法可以表示使用 noscript 特性的文档, 但 DOM 和 XML 语法却不能。 包含 "-->" 的注释只能在 DOM 中表示,HTML 和 XML 语法却不行。

1.9 本标准的结构

This section is non-normative.

本标准分为以下主要的部分:

概述
为 HTML 标准提供上下文的非规范性材料。
通用基础设施
合规的类、算法、定义、标准其余部分的通用基础。
HTML 文档的语义,结构,与 API
文档由元素构成,这些元素使用 DOM 组成一棵树。 这部分定义了该 DOM 的特性,介绍了所有元素共同的特性,以及在定义元素时用到的概念。
HTML 元素
每个元素都有一个预定义的含义,本章便解释了这些含义。 也给出了作者使用这些元素的规则,以及用户代理处理这些元素的要求。 这里包含了大量的 HTML 独有的特性,例如视频播放和副标题,表单控件和表单提交, 以及名为 HTML canvas 的 2D 图形 API。
微数据
本标准介绍了为文档增加机器可读注解的机制,这样工具可以从文档中抽取键值对的树。 这部分文档描述了该机制 和用于将 HTML 文档转换为其他格式的一些算法。 这部分还为联系信息、日历事件和许可协议定义了一些示例的微数据词汇。
用户交互
HTML 文档可以提供一些用户与内容交互以及用户修改内容的机制,在本章中给出了这些机制的描述。 比如焦点的工作机制、以及拖放操作。
加载 Web 页面
HTML 文档不是空中楼阁 — 这部分定义了很多影响处理多页面环境的特性,比如 Web 浏览器和 Web 应用的离线缓存。
Web 应用 API
这部分介绍了 HTML 应用脚本的基本特性。
Web workers
这部分定义了 JavaScript 后台线程的 API。
通信 API
这部分描述了 HTML 编写的应用可用来与同一客户端中的,不同域名的其他应用通信的一些机制。 也介绍了一个服务器推送事件流机制,称为 Server Sent Events 或 EventSource, 以及一个为脚本提供的双向全双工套接字协议,称为 Web Sockets。
Web storage
这部分定义了一个基于键值对的客户端存储机制。
HTML 语法
XML 语法
只有表示为序列化的形式并发送给其他人,所有的这些特性才会有意义。 所以这两部分定义了 HTML 和 XML 的语法 ,以及如何使用这些语法来解析内容的规则。
渲染
这部分定义了 Web 浏览器默认的渲染规则。

还有一些附录,列出了 废弃的特性IANA 考虑,以及一些索引。

1.9.1 如何阅读本标准

阅读本标准的方式与其他标准类似。首先应该完整地阅读多次,然后至少倒着读一次, 然后应该从目录中随机选入章节并跟着所有交叉引用读一次。

如下面一致性要求部分所述,本标准描述了各一致性等级的一致性标准。 特别地,有些一致性要求适用于生产者(例如作者和他们创建的文档), 也有一些适用于消费者(例如 Web 浏览器)。 他们的要求是不同的:对生产者的要求声明了什么是允许的,而对消费者的要求声明了软件的行为。

例如,“foo 属性的值必须是一个合法的整数” 是对生产者的要求,因为它规定了允许的取值;相反, “foo 属性的值必须使用 解析整数的规则来解析” 是对消费者的要求,因为它描述了如何处理内容。

对生产者的要求不会对消费者产生任何影响。

继续上述例子,“属性值必须是合法的整数”刻意地没有暗示对消费者的要求。 事实上消费者可能被要求把该属性当做透明的字符串,完全不关心它的值是否满足要求。 也可能被要求以指定的规则来解析它的值(就像上述例子中那样),这些规则就定义了如何处理不合法的值(在本例子中就是非数字的值)。

1.9.2 排版惯例

这是定义、要求,或者解释。

这是注意事项。

这是翻译者的注释。

这是例子。

这是未解决的问题。

这是警告

[Exposed=Window]
interface Example {
  // 这是一个 IDL 定义(接口描述语言)
};
variable = object . method( [ optionalArgument ] )

这是给作者看的,描述了接口的使用。

/* 这是一个 CSS 片段 */

术语的定义标记为 这样。 该术语的使用标记为 这样这样

元素、属性或 API 的定义标记为这样。 该元素、属性或 API 的引用标记为 这样

其他代码片段标记为这样

变量标记为这样

在算法中,同步部分的步骤标记为 ⌛。

有些情况下,要求以列表的形式给出,列表项包括条件和对应的要求。 在该情况下,适用于某项条件的要求紧跟着条件出现,这些要求的条件可能有很多个。例如:

这是一个条件
这是另一个条件
这是适用于上述条件的要求
这是第三个条件
这是适用于第三个条件的要求

1.10 HTML 的简单介绍

This section is non-normative.

一个基本的 HTML 文档看起来像这样:

<!DOCTYPE html>
<html lang="en">
 <head>
  <title>Sample page</title>
 </head>
 <body>
  <h1>Sample page</h1>
  <p>This is a <a href="demo.html">simple</a> sample.</p>
  <!-- this is a comment -->
 </body>
</html>

HTML 文档由树状的元素和文本组成。源码中每个元素由 一个 开始标签(例如 "<body>") 和一个 结束标签(例如 "</body>")表示。 (某些开始标签和结束标签在某些情况下可以 省略。)

标签的嵌套必须使所有标签都完全在其他标签内部,不应出现重叠:

<p>This is <em>very <strong>wrong</em>!</strong></p>
<p>This <em>is <strong>correct</strong>.</em></p>

本标准定义了 HTML 中使用的一些元素,以及它们的嵌套规则。

元素可以有属性来控制元素的行为。在下面的例子中是一个 超链接, 由一个a元素和它的 href 属性组成:

<a href="demo.html">simple</a>

属性 应放置在开始标签中,由 属性名属性值构成, 以 "=" 分隔。 如果不包含空格" ' ` = <>, 属性值可以保持 没有引号 ; 否则必须使用单引号或双引号。 如果属性值是空字符串,属性值以及 "=" 可以一起省略。

<!-- empty attributes -->
<input name=address disabled>
<input name=address disabled="">

<!-- attributes with a value -->
<input name=address maxlength=200>
<input name=address maxlength='200'>
<input name=address maxlength="200">

HTML 用户代理(比如 Web 浏览器)解析这些标记,把它转化为 DOM(Document Object Model)树。 DOM 树是文档在内存中的表示。

DOM 数包含若干种节点,具体地:DocumentType 节点、 Element节点、Text 节点、Comment 节点, 以及有时会出现的 ProcessingInstruction 节点。

本章顶部的代码片段将会转化为下列 DOM 树:

树中的document 元素html 元素, 在 HTML 文档的这一位置总是应该有这样一个元素。它包含两个元素, headbody,以及它们之间的一个 Text 节点。

DOM 树中的 Text 节点比你预想的要多,因为源码包含一些空格(表示为"␣")和换行("⏎"), 这些都会变成 DOM 中的 Text 节点。然而因为历史原因,并非所有这些源码中的空格和换行都出现在 DOM 中。 具体地,所有head开始标签前的空白都会被悄悄地丢掉,所有body结束标签后的空白都会出现在body的尾部。

head 元素包含一个 title 元素,其中包含一个 内容为 "Sample page" 的 Text 节点。类似地,body 元素包含一个 h1 元素,一个p 元素,和一个注释。


页面中的脚本可以操作该 DOM 树。脚本(比如 JavaScript)是可以使用 script标签或 事件处理内容属性内嵌的小程序。 比如下面是一个表单,其中的脚本设置了表单中output元素的内容并输出 "Hello World":

<form name="main">
 Result: <output name="result"></output>
 <script>
  document.forms.main.elements.result.value = 'Hello World';
 </script>
</form>

DOM 树中的每个元素表示为一个对象,这些对象提供 API 以供操作。 例如,一个链接(比如上述树中的a元素)的 "href"属性可以通过多种方式改变:

var a = document.links[0]; // obtain the first link in the document
a.href = 'sample.html'; // change the destination URL of the link
a.protocol = 'https'; // change just the scheme part of the URL
a.setAttribute('href', 'https://example.com/'); // change the content attribute directly

由于 DOM 树是实现者(尤其是像 Web 浏览器这样的交互式实现)用来处理和显示 HTML 文档的, 本标准更多地是按照 DOM 树来介绍的,而不是按照上面描述的标记代码。


HTML 文档表示了交互式内容的一种媒体无关的描述。HTML 文档可能会渲染在屏幕、语音合成器、或者盲文点触设备。 为了精确地控制渲染行为,作者可以使用一个像 CSS 这样的样式语言。

在下列例子中,使用 CSS 将页面设置为蓝底白字。

<!DOCTYPE html>
<html lang="en">
 <head>
  <title>Sample styled page</title>
  <style>
   body { background: navy; color: yellow; }
  </style>
 </head>
 <body>
  <h1>Sample styled page</h1>
  <p>This page is just a demo.</p>
 </body>
</html>

关于更多 HTML 的使用细节,鼓励作者参考教程和指南。 本标准中的一些示例可能也有用,但新手作者需要注意本标准必须非常详细地定义该语言, 以至于一开始可能很难理解。

1.10.1 使用 HTML 编写安全应用

This section is non-normative.

当使用 HTML 创建交互式网站时,需要注意避免引入漏洞,使得攻击者通过这些漏洞危害网站本身或网站用户信息的完整性。

对这一问题的全面研究超出了本文档的范围,我们强烈建议网站作者去更详细地研究这一问题。 即便如此,本节尝试对 HTML 应用程序开发中的一些常见陷阱作简单介绍。

Web 的安全模型基于“域”的概念,因此 Web 上许多潜在的攻击涉及跨域操作。[ORIGIN]

不验证用户输入
跨站脚本(XSS)
SQL 注入

当接受不可信输入时(例如文本评论这样的用户生成内容,URL 参数中的值,来自第三方网站的消息等), 必须在使用前验证数据,并在显示时正确转义。 否则就会允许恶意的用户执行各种攻击, 这些攻击可能是轻微的,例如提供诸如负的年龄这样的假的用户信息; 也可能是严重的,例如在每次用户查看包含该信息的页面时执行脚本; 也可能是传播性的攻击导致灾难性后果,比如删除服务器中的所有数据。

当编写过滤器验证用户输入时,过滤器应当是基于白名单的,允许已知的安全构造并禁止所有其他输入。 基于黑名单的过滤器(禁止已知的错误输入并允许其他所有输入)是不安全的, 因为并不是所有错误输入都是已知的(因为它可能会在未来发明)。

例如,一个页面查看它的 URL 查询字符串来决定显示的内容, 然后网站将用户重定向到显示该消息的页面。比如:

<ul>
 <li><a href="message.cgi?say=Hello">Say Hello</a>
 <li><a href="message.cgi?say=Welcome">Say Welcome</a>
 <li><a href="message.cgi?say=Kittens">Say Kittens</a>
</ul>

如果这一消息没有转义就显示给用户,恶意的攻击者可能会构造一个包含脚本元素的 URL:

https://example.com/message.cgi?say=%3Cscript%3Ealert%28%27Oh%20no%21%27%29%3C/script%3E

如果攻击者随后说服受害者访问此页面,攻击者选择的脚本将在页面上运行。 这样的脚本可以执行任意的恶意操作,只要是站点提供的。 例如站点是电子商务商店,这样的脚本可以导致在用户不知情的情况下进行任意的购买。

这称为跨站脚本攻击。

有很多构造可以欺骗网站执行代码。以下是网站作者在编写白名单过滤器时应考虑的事项:

跨站请求伪造 (CSRF)

如果网站允许用户提交的表单产生用户相关的影响,例如使用名字在论坛上发布消息, 进行购买或申请护照,那么很有必要核实该请求确实是用户有意发起的, 而不是由另一个站点欺骗用户不知情地发起请求。

该问题的存在是因为 HTML 表单可能被提交到其他域名。

站点可以通过为表单填充用户相关的隐藏标记或检查所有请求的`Origin`头字段, 来防止这样的攻击。

Clickjacking

如果页面为用户提供的界面中包含用户可能不希望执行的操作时, 该页面应当经过特殊设计来避免用户被欺骗以激活该界面的可能性。

一种用户被欺骗的可能是,如果恶意站点将受害站点放在一个小的 iframe 中然后让用户去点击, 例如让用户玩一个反应类游戏。一旦用户开始玩这个游戏,恶意站点可以在用户正要点击时快速地将这个 iframe 放到鼠标光标下。 以此来欺骗用户点击受害站点的界面。

为了避免这种情况,鼓励不期望在 iframe 下使用的站点只有检测(例如通过比较window对象和top属性的值) 到它们不在 iframe 下时才激活它们的界面。

1.10.2 使用脚本 API 时常见的陷阱

This section is non-normative.

HTML 中的脚本有着"运行到完成"的语义,这意味着浏览器通常在执行任何其他操作 (诸如触发进一步的事件或继续解析文档)之前会不中断地执行脚本。

另一方面,HTML 文件的解析是逐步发生的,这意味着解析器可以在任何地方暂停来让脚本运行。 这通常是一件好事,但确实意味着作者需要小心地避免在事件可能已经触发之后才绑定事件处理程序。

有两项技术能够可靠地完成这件事情:使用 事件处理程序内容属性, 或者在同一脚本中创建元素和添加事件处理程序。后一种更为安全,因为如前所述, 脚本会在进一步的事件发生前一直运行到完成。

一个可以表示此种情形的例子是img元素和load事件。 该事件在元素解析完成时就会触发,特别是当图片已经被缓存之后(这很常见)。

这里,作者在img标签上使用 onload 事件处理程序 来捕捉 load 事件:

<img src="games.png" alt="Games" onload="gamesLogoHasLoaded(event)">

如果使用脚本添加元素,那么只要在同一脚本中添加事件处理函数,该事件就不会被错过:

<script>
 var img = new Image();
 img.src = 'games.png';
 img.alt = 'Games';
 img.onload = gamesLogoHasLoaded;
 // img.addEventListener('load', gamesLogoHasLoaded, false); // would work also
</script>

然而如果作者首先创建了img元素,然后在另一个单独的脚本中添加了事件监听器, 那么有可能load事件会在两者之间触发,导致它被错过:

<!-- Do not use this style, it has a race condition! -->
 <img id="games" src="games.png" alt="Games">
 <!-- the 'load' event might fire here while the parser is taking a
      break, in which case you will not see it! -->
 <script>
  var img = document.getElementById('games');
  img.onload = gamesLogoHasLoaded; // might never fire!
 </script>

1.10.3 编写 HTML 时如何发现错误:验证器和一致性检查器

This section is non-normative.

鼓励作者使用一致性检查器(又称验证器)来发现常见的错误。 WHATWG 维护着这种工具的一个列表:https://validator.whatwg.org/

1.11 对页面作者的一致性要求

This section is non-normative.

与以前版本的 HTML 规范不同,此规范不仅定义了对有效文档的处理, 也详细定义了对无效文档的处理过程。

然而,即使无效内容的处理在大多数情况下是良好定义的,文档的一致性仍然很重要: 在实践中,互操作性(所有实现以可靠和相同或等同的方式处理特定内容的情况)并不是文档一致性要求的唯一目标。 本节详细地介绍了合法文档和错误文档仍然有所区别的一些常见原因。

1.11.1 表示性的标记

This section is non-normative.

先前 HTML 版本的大多数表示性特性不再被允许。一般来说,表示性的标记有这样一些问题:

表示性元素的使用导致较差的可访问性

尽管使用显示性的标记也可以为使用辅助技术(Assistive Technologies,AT)的用户 提供可接受的体验(比如使用 ARIA),但这样做显然比使用适当的语义标记更加困难。 此外,即使使用这样的技术也不能帮助那些既没有 AT 又没有图形的用户(比如使用文本模式浏览器的用户)访问页面。

另一方面,使用媒体无关的标记为编写更多用户(比如文本浏览器的用户)可用的文档提供了简单的方式。

更高的维护成本

使用样式无关的标记编写的站点,显然更容易维护。比如,对于到处都在使用 <font color=""> 的站点,更改颜色需要更改整个站点, 然而对基于 CSS 的站点做类似的改动,只需更改一个文件。

更大的文档大小

表示性标记往往会增加冗余,因此导致更大的文档大小。

出于这些原因,在本版本的 HTML 中移除了表示性的标记。 这一改动并不突然,HTML4 在很多年前就已经不推荐使用表示性标记, 并提供了一种模式(HTML4 Transitional) 来帮助作者从表示性标记进行迁移; 后来 XHTML 1.1 更进一步地一起废弃了那些特性。

HTML 中唯一保留下来的表示性标记特性是 style 属性和 style 元素。 生产环境中使用 style 属性也在某种程度上不再推荐, 但在创建原型(这些规则之后可以直接移动到单独的样式表中) 以及在特殊情况下(当单独的样式表不方便时)提供特定样式很有用。 类似地,style 元素在引入外部样式内容或者提供页面特定样式时很有用。 但一般来说,当样式适用于多个页面时,外部样式表可能更加方便。

值得注意的是有些先前的表示性元素在本标准中已经被重新定义为媒体无关的: b, i, hr, s, small, and u.

1.11.2 语法错误

This section is non-normative.

限制 HTML 的语法是为了避免各种各样的问题。

不直观的错误处理行为

某些不合法的语法构造在解析后会导致很不直观的 DOM 树。

例如,以下标记片段会导致 DOM 树中的 hr 元素 在相应的 table 元素之前

<table><hr>...
可选错误恢复的错误

为了允许在受控环境中使用的用户代理不必实现更奇怪和复杂的错误处理规则, 允许用户代理在遇到解析错误时失败。

错误处理行为与流式用户代理不兼容的的错误

一些错误处理行为(比如上面提到的<table><hr>...) 与流式用户代理(不存储状态且通过一次遍历来处理 HTML 文件的用户代理)不兼容。 为了避免与这样的用户代理的互操作性问题,任何导致该行为的语法都是无效的。

会导致信息集强制的错误

当一个基于 XML 的用户代理连接到一个 HTML 解析器时, 某些 XML 强制的不变式(比如元素或属性名不可包含多个冒号)可能被 HTML 文件违反。 处理这种情况可能要求解析器将 HTML DOM 信息强加给 XML 兼容的信息集。 要求这一处理的多数语法构造都是不合法的。 (包含两个连续的间隔符的注释,或以一个间隔符结尾的注释是特例,这在 HTML 语法中是允许的)。

这一规则意味着基于 XML 的用户代理只需连接一个 HTML 解析器(Parser)即可拥有理解 HTML 的能力。所以 HTML 与 XML 只是语法有所不同, 表达语义的能力应当是等价的。

会导致性能下降的错误

某些语法构造可能导致很差的性能。为了阻止这些构造的使用,通常把它们归为不合规范的。

例如,下列标记会导致很差的性能,因为所有未闭合的 i 元素必须在每个段落中重新构造, 导致每个段落中的元素累加地增多:

<p><i>She dreamt.
<p><i>She dreamt that she ate breakfast.
<p><i>Then lunch.
<p><i>And finally dinner.

该片段的结果 DOM 将会是:

涉及到脆弱的语法构造的错误

由于历史原因有一些语法构造相对脆弱。为了避免用户意外地掉到坑里,它们也被归为不合规范的。

例如,即使省略了关闭分号,对属性中命名的字符引用的解析也会发生。 可以安全地引入一个&以及紧随其后的不构成特殊命名的字符引用, 但如果这些字母改成构成命名的字符引用,它们将会被解释为那个特殊字符。

在这个代码片段中,属性值是“?bill&ted”:

<a href="?bill&ted">Bill and Ted</a>

在下面的代码片段中,属性值实际上会变成“?art©”, 而不是 期望的 “?art&copy”, 因为即使没有最后的分号“&copy”也会一样地被处理为 “&copy;”最终被解释为“©”:

<a href="?art&copy">Art and Copy</a>

为了避免这一问题,要求所有命名的字符引用以分号结束, 所有使用命名字符引用但未添加分号的都被标记为错误。

因此正确地表达上述情况的方式如下:

<a href="?bill&ted">Bill and Ted</a> <!-- &ted is ok, since it's not a named character reference -->
<a href="?art&amp;copy">Art and Copy</a> <!-- the & has to be escaped, since &copy is a named character reference -->
涉及旧用户代理中的已知互操作性问题的错误

某些语法构造在旧的用户代理中会造成一些已知的细微或严重的问题。 因此他们被标记为不合规范的来帮助作者避免这些问题。

例如 U+0060 重音符(`)不允许出现在没有引号的属性中。 因为在某些旧用户代理中,它有时会被当做一个引号。

另一个例子是必须使用 DOCTYPE 来触发 非怪异模式, 因为旧用户代理在 怪异模式 下的行为通常都没有文档。

可能引发对作者的安全攻击的错误

某些限制纯粹是为了避免已知的安全问题。

例如,对使用 UTF-7 的限制纯粹是为了避免作者成为使用 UTF-7 的已知跨站脚本攻击的的目标。[UTF7]

作者的意图不清楚的情况

作者意图不清楚的标记通常被划为不规范的。 尽早修复这些错误会使得后续维护更为容易。

例如,作者是要将以下内容作为 h1 标题还是 h2 标题的意图并不明确:

<h1>Contact details</h2>
可能是拼写错误的情况

当用户发生了拼写错误,提早捕获该错误是有帮助的,因为这可以节省作者很多调试时间。 因此本标准通常认为使用与本标准中定义的名字不匹配的元素名、属性名等是错误的。

例如,如果作者键入<capton> 而不是 <caption>,这将被标记为错误,作者可以立即更正错字。

将来可能会干扰新语法的错误

为了允许将来扩展语言语法,某些本来无害的特性也是不允许的。

例如,在结束标签中的“属性”目前被忽略,但它们是非法的。 以防未来使用该语法特性的语言变更与已部署(但是合法的!)内容产生冲突。

一些作者发现,在实践中总是用引号包含所有的属性并且总是包含所有的可选标签很有帮助, 相比于利用 HTML 语法的灵活性而带来的一点简洁,更偏好这一做法带来的一致性。 为了协助这样的作者,一致性检查器可以提供执行这一惯例的运行模式。

1.11.3 内容模型和属性值的限制

This section is non-normative.

除了语言的语法,本标准还对如何指定元素和属性做出了限制。 这些限制是出于类似的原因:

语义可疑的内容

为了避免误用定义了含义的元素, 定义内容模型时,限制了可疑的元素嵌套方式。

例如,本标准不允许 section 元素嵌套在 kbd 元素中,因为作者不太可能表示 应该键入整个 section

表达的语义存在冲突

类似地,为了让作者对元素使用中的错误引起注意, 表达出的语义存在明显的矛盾也被认为是一致性错误。

例如下面的片段中的语义是毫无意义的: 分隔符不能同时是单元格,单选按钮也不能是进度条。

<hr role="cell">
<input type=radio role=progressbar>

另一个例子是对ul元素的内容模型的限制, 该限制只允许 li 子元素。根据定义列表只可包含一些列表项。 所以如果 ul 元素包含一些除了 li 之外的元素, 它的含义就不清楚了。

默认样式可能会导致困惑的情况

某些元素有一些默认样式和行为,它们的某些组合可能会令人困惑。 如果存在没有这一问题的等效替代,就不允许这样令人困惑的组合。

例如,div 元素会被渲染为 block boxesspan 元素则为 inline boxes。将 block box 放到 inline box 中就会导致不必要的困惑;因为只嵌套 div 元素,或只嵌套 span 元素,或在div元素中嵌套 span 元素都可以与在span元素中嵌套div元素 达到同样的目的。但只有后者涉及到在 inline box 中嵌套 block box, 所以后者的组合方式是不允许的。

另一个可能的例子是 交互内容 不可嵌套。例如: button 元素不可包含 textarea 元素。 这是因为这样嵌套交互元素可能对用户造成困惑。可以并排放置这些元素。

对本标准可能的误解

有时,某些禁止是因为允许它将可能会让作者困惑。

例如,设置 disabled 属性为 "false" 是不允许的,因为表面上看起来它的含义是元素可用, 但实际上含义是元素被 禁用 (实现中起作用的是该属性是否存在,而非它的值)。

纯粹为了简化语言而强加的限制

一些一致性错误简化了作者需要学习的语言。

例如,area 元素的 shape 属性,在实践中虽然同时接受 circcircle 取值并作为同义词,但禁止 circ 值的使用, 以此来简化教程和其他学习材料。同时允许它们并没有好处, 但它们可能在学习语言时造成额外的困惑。

解析器的一些怪异行为

某些元素的解析有点奇怪(通常是由于历史原因), 它们的内容模型限制旨在避免作者碰到这些问题。

例如,phrasing content 中不允许 form 元素,因为当解析 HTML 时, form 元素的开始标签将会产生一个 p 元素的关闭标签。因此下面的标记会产生两个 段落(而不是一个):

<p>Welcome. <form><label>Name:</label> <input></form>

与下面代码的解析结果完全一样:

<p>Welcome. </p><form><label>Name:</label> <input></form>
可能导致难以调试的脚本错误的情况

有些错误旨在避免难以调试的脚本问题。

比如,这就是为什么有两个等值的 id 属性是不合法的。 重复的 ID 导致选择到错误的元素,有时会产生难以确定原因的灾难性后果。

会浪费编写时间的错误

某些构造被禁止是因为历史上它们曾浪费大量的编写时间。 鼓励作者避免使用这些构造,将来可以节省很多时间。

例如,script 元素的 src 属性会导致元素的内容被忽略。 然而这并不明显(尤其是元素内容是可执行脚本时)— 这会导致作者花费大量时间尝试调试内联脚本,却没意识到它并未执行。 为了减少这一问题,在本标准中src 属性出现时,script元素中不允许存在可执行脚本。 这意味着作者在验证他们的文档时,不太可能在这样的错误上浪费时间。

影响作者在 HTML 和 XML 语法间迁移的部分

有些作者喜欢编写用 XML 和 HTML 解释可以得到类似结果的文件。 由于种种微妙的复杂性(尤其是涉及脚本、样式、或其他任何自动的序列化), 一般并不鼓励这一做法,尽管如此,本标准也有一些限制意在在某种程度上减轻困难。 这让作者在 HTML 和 XML 语法之间迁移时,可以更容易地将其用于过渡步骤。

例如,围绕 langxml:lang 属性有一些复杂的规则, 就是为了让 HTML 和 XML 同步。

另一个例子可能是在 HTML 序列化中对 xmlns 属性值的限制,意在确保不管是 HTML 还是 XML 解析, 合法的文档中元素总在同一命名空间。

为将来扩充而保留的部分

对语法的某些限制是为了允许语言的未来版本中添加新的语法, 类似地,对元素和属性取值的内容模型的一些限制是为了允许将来对 HTML 词库进行扩充。

例如,限制 target 属性的值, 以 U+005F 下划线(_)起始的只能是特定的预定义值。这允许了在将来引入新的预定义值, 同时不会与作者定义的值产生冲突。

对其他标准的误用

某些限制意在支持其他标准作出的限制。

例如,使用媒体查询列表的属性只能使用 合法的 媒体查询列表,强调了遵循那一标准的一致性规则的重要性。

1.12 推荐阅读

This section is non-normative.

本标准的读者可能对以下文档感兴趣。

Character Model for the World Wide Web 1.0: Fundamentals [CHARMOD]

这个架构风格标准定义了 World Wide Web 中可互操作的文本操作。为其他标准的作者、软件开发者,以及内容开发者提供了通用的参考。 该标准构建在 Universal Character Set 之上,同时定义在 Unicode Standard 和 ISO/IEC 10646。 涉及的话题包括:字符、编码、字符串、引用处理模型、字符编码的选择和识别、字符转义,以及字符串索引。

Unicode 安全考虑 [UTR36]

由于 Unicode 包含大量的字符,引入了世界上不同的书写系统, 错误的使用会将程序和系统暴露在可能的安全攻击之下。随着越来越多的产品被国际化该问题尤为重要。 该标准描述了程序员、系统分析师、标准开发者,以及用户应当考虑的安全事项,为减少风险提供了明确的建议。

Web Content Accessibility Guidelines (WCAG) 2.0 [WCAG]

Web Content Accessibility Guidelines (WCAG) 2.0 对于提高 Web 内容的可访问性给出了广泛的建议。 遵循这些指导可以使更多的残障人士(包括失明和弱视、失聪和听觉损耗、学习和认知障碍、行动不便、语言障碍、光过敏等)可访问您的内容。 遵循这些指导也通常会使您的 Web 内容对普通用户更加可用。

Authoring Tool Accessibility Guidelines (ATAG) 2.0 [ATAG]

该标准为设计 Web 内容写作工具提供了指导意见,使得残障人士也可使用这些工具。 遵从这些指导的写作工具将会通过为残障作者提供可访问的用户界面以提升可访问性,以及为所有作者提供、支持和提升产出 Web 内容的可访问性。

User Agent Accessibility Guidelines (UAAG) 2.0 [UAAG]

该文档为设计降低残障人士 Web 访问门槛的用户代理提供了指导意见。 用户代理包括浏览器和其他获取和渲染 Web 内容的软件。 遵循这些指导的用户代理通过它自己的用户界面以及其他内部工具 (包括与其他技术通信的能力,尤其是辅助性技术)提升可访问性。 此外,除残障人士之外的所有用户都会发现遵循该标准用户代理更加可用。