这是一篇来自 Henri Sivonen 的客座文章,他一直在致力于 Firefox 的新 HTML5 解析器。HTML 解析器是浏览器中最复杂和最敏感的部分之一。它控制着 HTML 源代码如何转换为网页,因此对其进行更改非常罕见,并且需要进行充分的测试。虽然自 90 年代末 Gecko 首次问世以来,大部分代码都已重建,但解析器是“原始”代码中为数不多的几个例外。这将用一个新的解析器来替换旧的解析器,新的解析器速度更快,符合新的 HTML5 标准,并且还启用了许多新功能。
替换 Gecko 自 1998 年以来的旧 HTML 解析器的项目已经进行了一段时间了。该解析器现在默认在主分支上启用,因此您只需 下载一个 Nightly 版本 就可以尝试使用它,无需更改任何配置选项。
新的 HTML5 解析器带来了四个主要改进
- 您现在可以在 HTML5 页面中内联使用 SVG 和 MathML,无需使用 XML 命名空间。
- 解析现在是在 Firefox 的主 UI 线程之外完成的,从而提高了浏览器的整体响应能力。
- 它将
innerHTML
调用的速度提高了约 20%。 - 随着新解析器的发布,我们修复了 数十个长期存在的解析器相关错误。
使用 Firefox Nightly 或其他支持 HTML5 的浏览器尝试演示。它应该看起来像这样
什么是 HTML5 解析器?
Gecko 中的 HTML5 解析器根据 HTML5 解析算法 将字节流转换为 DOM 树。
HTML5 是第一个详细说明实现者如何解析 HTML 的规范。在 HTML5 之前,HTML 规范并没有说明如何将字节流转换为 DOM 树。理论上,HTML5 之前的 HTML 应该根据 SGML 来定义。这意味着有效的 HTML 文档的源代码和 DOM 之间存在着某种关系。但是,对于无效文档(而 Web 内容通常不是有效的 HTML4)来说,解析并没有得到很好的定义,而且理论上是 HTML 的一部分但实际并未被主流浏览器实现的 SGML 结构也存在。
由于缺乏适当的规范,浏览器开发人员不得不自行填补空白,并在对如何获得兼容行为存在疑问时,对市场份额最大的浏览器(最初是 Mosaic,然后是 Netscape,再然后是 IE)进行逆向工程。这导致了许多不成文的通用规则,但也导致了浏览器之间的行为差异。
HTML5 解析算法标准化了浏览器和其他使用 HTML 的应用程序可以收敛的定义明确的行为。根据设计,HTML5 解析算法适合处理现有的 HTML 内容,因此应用程序无需继续维护旧的解析器以处理旧内容。具体来说,在主分支的 Nightly 版本中,HTML5 解析器用于所有 text/html
内容。
它有何不同?
HTML5 解析算法有两个主要部分:标记化和树构建。标记化是将源流拆分为标签、文本、注释和标签内属性的过程。树构建阶段接受标签以及交错的文本和注释,并构建 DOM 树。HTML5 解析算法的标记化部分更接近于 Internet Explorer 的做法,而不是 Gecko 以前的做法。Internet Explorer 在一段时间内拥有最大的市场份额,因此站点通常经过测试以确保在经过 IE 的标记器处理后不会出现故障。树构建部分与 WebKit 已经实现的功能非常接近。在 HTML5 出现之前,在所有主要浏览器引擎中,WebKit 拥有最合理的树构建解决方案。
此外,新的 HTML5 解析器在主线程之外解析网络流。传统上,浏览器大多数任务都在主线程上执行。与 Gecko 的旧 HTML 解析器相比,HTML5 解析器的代码库更加易于维护,使得像在主线程之外解析这样的重大更改成为可能。
这对 Web 开发人员有什么意义?
上面提到的更改主要对浏览器开发人员感兴趣。HTML5 解析器的一个关键特性是您不会注意到有任何变化。
但是,也存在一项面向 Web 开发人员的重要新功能:内联 MathML 和 SVG。HTML5 解析从 XML 中解放了 MathML 和 SVG,并使它们在 Web 的主要文件格式中可用。
这意味着您可以将排版精美的数学公式包含在 HTML 文档中,而无需将整个文档重铸为 XHTML,更重要的是,无需将为您的站点提供支持的软件改造为输出格式良好的 XHTML。例如,您现在可以在 HTML 中内联包含二次方程式的解
同样,您也可以将可缩放的内联艺术作为 SVG 包含在内,而无需将 HTML 重铸为 XHTML。随着屏幕尺寸和像素密度的变化,使图形在所有缩放级别上都清晰可见变得越来越重要。虽然以前可以通过引用(使用 object
元素)在 HTML 文档中使用 SVG 图形,但在某些情况下,内联放置 SVG 更加方便。例如,警告符号之类的图标现在可以内联包含,而不是从外部文件包含。
创建一个以 <!DOCTYPE html>
开头的页面,并将这两段代码放入其中,它应该可以在新的 Nightly 版本中运行。
一般来说,如果您有一段 MathML 或 SVG 代码,您只需将 XML 标记内联粘贴到 HTML 中(如果存在,省略 XML 声明和文档类型)。有两点需要注意:标记不得使用元素的命名空间前缀(即没有 svg:svg
或 math:math
),并且 XLink 命名空间的命名空间前缀必须是 xlink
。
在上面的 MathML 和 SVG 代码片段中,您会看到上面的内联 MathML 和 SVG 代码比单纯将 XML 粘贴到 HTML 中更加 HTML 化,并且减少了冗余。没有命名空间声明,并且已省略属性值周围不必要的引号。引号省略有效,因为标签是由 HTML5 标记器处理的,而不是由 XML 标记器处理的。命名空间声明省略有效,因为 HTML5 树构建器不会使用看起来像命名空间声明的属性来为元素分配 MathML 属性或 SVG 属性。相反,<svg>
为分配到 DOM 中 SVG 命名空间的元素建立了一个范围,<math>
为分配到 DOM 中 MathML 命名空间的元素建立了一个范围。您还会注意到,MathML 示例使用了以前在 HTML 中不支持的命名字符引用。
以下是内联 MathML 和 SVG 解析的快速总结,供 Web 作者参考
<svg>
…</svg>
被分配到 DOM 中的 SVG 命名空间。<math>
…</math>
被分配到 DOM 中的 MathML 命名空间。foreignObject
和annotation-xml
(以及其他一些不那么重要的元素)建立了一个嵌套的 HTML 范围,因此您可以像预期的那样嵌套 SVG、MathML 和 HTML。- 解析器会对标记进行大小写校正,因此
<SVG VIEWBOX='0 0 10 10'>
在 HTML 源代码中有效。 - DOM 方法和 CSS 选择器区分大小写,因此您需要使用规范的大小写来编写 DOM 调用和 CSS 选择器,对于 SVG 的各个部分(例如
viewBox
)来说,规范的大小写是驼峰式。 - 如果
foo
是 MathML 或 SVG 元素(即不是 HTML 元素),则语法<foo/>
会立即打开并关闭foo
元素。 - 属性的标记化方式与在 HTML 中的标记化方式相同,因此您可以在与在 HTML 中相同的条件下省略引号(即,当属性值不是空字符串并且不包含空格、
"
、'
、`
、<
、=
或>
时)。 - 警告:由于重用了与旧版本兼容的 HTML 标记化,上述两个特性不能很好地结合使用。如果在最后一个属性值上省略引号,则必须在结束斜杠之前有一个空格。
<circle fill=green />
是有效的,但<circle fill=red/>
无效。 - 以
xmlns
开头的属性对最终使用的命名空间元素或属性没有任何影响,因此您不需要使用以xmlns
开头的属性。 - XLink 命名空间中的属性必须使用前缀
xlink
(例如xlink:href
)。 - 元素名称中不得包含前缀或冒号。
- SVG
script
元素的内容的标记化方式与在 XML 中的标记化方式相同,而不是像 HTMLscript
元素的内容的标记化方式。 - 当 SVG 或 MathML 元素打开时,
<![CDATA[
…]]>
部分按在 XML 中的方式工作。您可以使用它将文本内容隐藏在不支持text/html
中的 SVG 或 MathML 的旧浏览器中。 - MathML 命名字符可在文档中的任何位置(包括 HTML 内容)使用命名字符引用。
- 为了处理作者将部分 SVG 片段粘贴到 HTML 中(谁知道为什么)或将
<math>
标签用于非 MathML 目的的旧页面,尝试将各种常见的 HTML 元素作为 SVG 元素的子元素嵌套(没有foreignObject
)将立即退出 SVG 或 MathML 上下文。这可能会使一些错别字产生意想不到的效果。
66 条评论