3.4 理解HTML5的文档大纲
上一节讲了构成页面大纲的标题元素h1
~h6
。这一节将进一步讲解一些HTML5特有的影响文档大纲的元素。
你知道,使用标题元素可以为每个HTML文档定义一个基本的大纲,就像目录一样。现在,大纲还无法在页面中明确地显示出来(也许有一天浏览器会提供显示它的方法),但它提供的语义对搜索引擎和屏幕阅读器来说是非常有意义的。搜索引擎和屏幕阅读器通过大纲确定页面的结构并为用户提供相关信息。
在HTML5之前的HTML和XHTML中,h1
~h6
是创建文档大纲的全部元素。HTML5则提供了四个分块内容(sectioning content)元素──article
、aside
、nav
和section
。这些元素将文档划分为不同的区块,并定义了h1
~h6
(以及header
和footer
)元素的范围。
这意味着每个分块元素都有它自己的h1
~h6
层次结构,与这门语言早期的版本相比,这是一项重大的改进。同时,每个页面都可以有一个以上的h1
,而且HTML规范也推荐这样做(不过,下面我很快将要讲到,为什么应该限制h1
的数量)。
上述这些都会影响大纲。让我们比较一下两种等价的大纲,看看其工作原理。在两个例子中,不妨想象每个标题之后都有众多段落和其他内容。
第一个大纲只用了标题元素,它是完全有效的HTML5,那些拥有HTML和XHTML经验的人应该对它非常熟悉,如图3.4.1所示。
...
<body>
<h1>Product User Guide</h1>
<h2>Setting it Up</h2>
<h2>Basic Features</h2>
<h3>Video Playback</h3>
<h2>Advanced Features</h2>
</body>
</html>
图3.4.1 文档大纲版本1
第二个版本(如图3.4.2所示)既用了标题元素,又用了HTML5的section
元素(包含一个嵌套的section
元素)。(注意:缩进并不重要,它不会对大纲产生影响,但它可以让元素的包含关系显得很清晰。)
早先,我提到浏览器还无法将大纲显示出来。不过,可以使用Geoffrey Sneddon的HTML 5 Outliner(http://gsnedders.html5.org/outliner/)查看大纲。这是一个对文档大纲进行可视化显示的简单好用的工具。用该工具对上面的版本1和版本2生成大纲,不难发现,尽管它们的h1
~h6
标题层级并不相同,但大纲是一样的:
Product User Guide
Setting it Up
Basic Features
- Video Playback
- Advanced Features
- ...
- <body>
- <h1>Product User Guide</h1>
- <section>
- <h1>Setting it Up</h1>
- </section>
- <section>
- <h1>Basic Features</h1>
- <section> <!-- 嵌套的,因此是其父元素的子区块 -->
- <h1>Video Playback</h1>
- </section>
- </section>
- <section>
- <h1>Advanced Features</h1>
- </section>
- </body>
- </html>
图3.4.2 文档大纲版本2(与版本1的大纲相同,但是有含义的标记更多)
可以看到,版本2中每个section
元素都变成离它最近的h1
~h6
或分块内容祖先(这此例中,分块内容祖先仍是section
元素)的子区块。全部四个HTML5分块内容元素(article
、aside
、nav
和section
)都会如此,即使将它们混合到一起。
相比之下,如果版本2没有section
元素(可以称之为版本3,如图3.4.3所示),那么大纲会很不一样。
这时每个标题的重要性都是一样的(h1
),意即没有任何子标题(或子子标题):
Product User Guide
Setting it Up
Basic Features
Video Playback
Advanced Features
...
<body>
<h1>Product User Guide</h1>
<h1>Setting it Up</h1>
<h1>Basic Features</h1>
<h1>Video Playback</h1>
<h1>Advanced Features</h1>
</body>
</html>
图3.4.3 文档大纲版本3(与版本1和版本2的大纲并不相同)
拥有相同含义的大纲(即版本1和版本2),尽管都是有效的,但版本2更为可取,因为section
元素的语义更为明确。实践中,可以用一个article
元素将版本2的全部内容包起来,在这种情形下,加上article
更为合理(尽管所生成的大纲会略有不同)。图3.4.4展示了一个例子。
- ...
- <body>
- <article>
- <h1>Product User Guide</h1>
- <section>
- <h1>Setting it Up</h1>
- </section>
- <section>
- <h1>Basic Features</h1>
- <section>
- <h1>Video Playback</h1>
- </section>
- </section>
- <section>
- <h1>Advanced Features</h1>
- </section>
- </article>
- </body>
- </html>
图3.4.4 具有明确语义的大纲
别忘了,每个标题之后应该紧跟着相关的文本、图像和其他内容(即将在后面了解到)。不过现在这些内容都没有加进来,让你可以专注于标题和大纲。
- 迎合当前生态系统
但是,等等!还要对代码做一项调整。还记得我说过“下面我很快将要讲到,为什么应该限制h1
的数量”吗?尽管每个分块内容元素(article
、aside
、nav
和section
)都可以从h1
开始其标题层级,但这并不是强制性的。实际上,在可预见的将来,如果分块内容元素代表的是已经存在的h1
的子标题,则最好使用h2或更低级别的标题开始每个区块。
下面是这样做的原因。
在不断演进的万维网世界,有大量变化的部分。像HTML5这样的新规范在最终确定(需要过一些年,目前HTML5还没有最终确定)之前,每天都在变化。新的浏览器发布了,新版本的屏幕阅读器和其他辅助技术推出了,但它们的步调并不会完全同步。
相反,每个浏览器都会逐步添加功能(这多半是好事),但不一定是与其竞争对手相同的功能(这不太好),而且肯定不会是与其竞争对手同步的时间表。屏幕阅读器也是同样的情况。因此,尽管现代浏览器都支持大量HTML5特性,在本书写作时没有一个浏览器能将HTML5大纲呈现给屏幕阅读器,而屏幕阅读器也无法将其呈现给用户。
简而言之,这意味着屏幕阅读器和其他辅助技术还无法区分直接放在body
里的h1
和包含在article
、aside
、nav
和section
里面的h1
。在它们看来,这些h1
都是顶层的h1
。Opera布道者Bruce Lawson是我知道的第一个指出这一点的人(www.brucelawson.co.uk/2009/headings-in-html-5-and-accessibility/;注意这个URL中的其他一些信息已经过时了,因为从那时起规范已经发生了变化。另参见他与Remy Sharp的新著Introducing HTML5)。
然而,屏幕阅读器用户却没有时间等待万维网跟上他们的需求。它们将继续利用标题来获取页面内容概览,对页面进行导航。而有含义的标题层级关系将让这变得更为容易,使访问者拥有更好的体验。
因此,在生态系统赶上来之前,使用h1
~h6
明确地表现层次关系,就像没有分块内容元素一样,会让你和你的用户感觉更好。Lawson等人推荐这种方法,我也是。
下面看看应该怎样做,参见图3.4.5。
- ...
- <body>
- <article>
- <h1>Product User Guide</h1>
- <section>
- <h2>Setting it Up</h2>
- </section>
- <section>
- <h2>Basic Features</h2>
- <section>
- <h3>Video Playback</h3>
- </section>
- </section>
- <section>
- <h2>Advanced Features</h2>
- </section>
- </article>
- </body>
- </html>
图3.4.5 版本4(所有4个版本的推荐方法)
原先处于section
元素第一层的h1
现在是h2
。标题Video Playback所在的section
嵌套在另一个section
里面,它原先是h1
,现在是h3
。文档大纲并未改变,只是标题层级改变了。
这个例子中只有h1
~h3
不过,如果需要,也可以使用h4
~h6
。例如,Video Playback的子标题应该是一个h4
(视情况可加上一个分块父元素),以此类推。
记住,这种推荐做法对所有的分块内容元素(article
、aside
、nav
和section
)都管用,而不仅仅是例子中出现的分块内容元素。
- 小结
如果还没有完全掌握HTML5的文档大纲,建议你重读一遍关于它的讨论。看起来容易,做起来难。强烈建议你创建多种测试页面,比较它们在HTML5 Outliner中的结果,从而更好地理解大纲算法的原理。在做实际项目时,也应使用Outliner,确保页面结构是符合预期的。首先,确保对HTML5页面进行验证,消除编码错误(参见20.5节,http://validator.nu/与http://validator.w3.org/两个网址均可)。
提示 不要留下这样一种印象,即必须使用一个
article
,或者section
必须(也只能)嵌套在一个article
里面。我们讨论的例子只是使用这些元素的一种方式,而事实上,同样的内容也可以用其他的方式进行标记,它们仍然是有效的HTML5。稍后我们会详细讲解article
和section
,根据内容的不同,它们有一些不同的应用场景。
HTML5大纲算法对聚合内容的好处
目前你已看到,作为分块内容元素,根据HTML5的大纲算法,每个
article
、aside
、nav
和section
都有其自身的大纲,该大纲可以从h1
开始,一直到h6
。除了给文档标题增加了灵活性,这还有另外一个不那么明显的好处:当内容出现在其他页面甚至其他网站时,不会破坏父文档的大纲,其自身的大纲也完好无损。
如今,在网站之间共享内容已变得越来越普遍了。这样的例子包括新闻聚合网站、带RSS源的博客、Twitter源,等等。你即将在3.9节中了解到,
article
元素代表一个独立的容器,它可以被聚合(并非必需,只在恰当的时候可以这样做)。想象下面的
article
显示在另一个网站的情形:
- …
- <h2>News from around the Web</h2>
- <article>
- <h1>Local Teen Prefers Vinyl over Digital</h1>
- <p>A local teen has replaced all her digital tracks with vinyl. "It's groovy," she said, on the record.</p>
- <h2>Hooked after First Album</h2>
- …
- </article>
- …
将代码放入HTML5 Outliner,将会看到其大纲为:
News from around the Web
1. Local Teen Prefers Vinyl over Digital
1. Hooked after First Album
因此,即使Local Teen标题比它上面的
h2
的层级更高(h1
),它仍然是h2
的子标题,因为它包含在h2
下面的article
中。而Hookedh2
则是Newsh2
的子子标题,不是在平等的层级。将News标题改为
h3
、h4
或任何层级,大纲都会保持不变。Local Teen和Hooked也是一样,只要保持Local Teen的标题层级比Hooked的高。