第 2 章 用语义元素构造网页

第 2 章 用语义元素构造网页

从Web诞生到现在的20年间,网站发生了天翻地覆的变化。不过,最让人叹为观止的,还不是Web的变化有多大,而是最古老的HTML元素到今天依然被沿用着!事实上,Web开发人员在构建现代网站时使用的HTML元素,与10年前构建网站时使用的HTML元素别无二致。

有一个元素特别值得一提,那就是温和谦恭的<div>(division,分区)元素,它堪称每一个现代网页的柱石。利用<div>元素,可以把整个HTML文档分隔为页眉、侧边面板、导航条,等等。再辅以少量可靠的CSS,就可以把这些区块转换成带边框的盒子或带阴影的分栏,而且各就各位。

这种<div>加样式的技术既简明又强大,还非常灵活——但不够透明。在查看别人的源代码时,必须费点劲才能知道哪个<div>表示什么,而整个页面又是怎么搭建起来的。为了理解页面的构造,不得不在标记、样式表和浏览器显示的页面之间跳来转去。特别是在破解别人编写的不怎么符合最佳实践的页面时,即便你也在自己的网站中应用了同样的设计技术,也少不了会面对这种困惑。

这种情况引发了人们的思考。是不是可以用更好的东西来代替<div>?这种东西需要发挥与<div>一样的作用,但却能传达出更多的语义。而且,要能够把侧边栏与页眉分开,以及把广告条与菜单分开。HTML5为此引用了一组构造页面的新元素,实现了Web开发人员的这一夙愿。

提示 如果你的CSS技能尘封已久,急需温故知新,然后才能看懂样式表,那说明你还没法学习这一章。好在附录A中包含一个简明的CSS教程,在那里可以找到CSS知识的基本介绍。

2.1 语义元素

要想让网页的结构更清晰,需要使用HTML5中新的语义元素(semantic element)。这些元素可以为它们标注的内容赋予额外的含义。例如,新的<time>元素用于在网页中标注一个有效的日期或时间。下面就是<time>元素最简单的用例:

Registration begins on <time>2014-11-25</time>.

这行代码在网页中呈现的结果如下所示:

Registration begins on 2014-11-25.

最关键的是要理解,<time>元素没有任何内置的样式。实际上,网页的读者也没有办法知道有一个额外的元素包含了日期。你可以使用样式表为<time>元素添加样式,但默认情况下,<time>元素中的文本与普通文本没有任何区别。

设计<time>元素的用意是让它来包含一小段信息。不过,大多数HTML5语义元素的用途是标识页面中的一个内容区块。比如,<nav>元素用于标识一组导航链接。而<footer>元素用于标识通常放在页面底部的文脚(或页脚)。算起来,大概有十几个类似的新元素。

注意 尽管语义元素在HTML5的新功能里不怎么起眼,但它们的数量却不少。HTML5新增的大部分元素都是语义元素。

所有语义元素都有一个显著的特点:不真正做任何事。相对来说,<video>元素则囊括了在页面中充当视频播放器的全部能力(参见5.2.5节)。有读者可能会问了,既然它们不会改变网页的外观,那为什么还要使用这些新元素呢?

有如下几条理由。

  • 容易修改和维护。解读传统的网页比较困难。要想理解整体布局和不同区块的重要程度,必须得一遍一遍地看网页的样式表。但通过使用HTML5的语义元素,通过标记就可以传达出额外的结构化信息。这样,等你几个月后再回头修改网页,就不会像以前那么头疼了。当然,如果是其他人需要帮你改进页面,使用语义元素就显得更重要了。

  • 无障碍性。现代Web设计的一个重要主题,就是让任何人都能无障碍地访问网页。换句话说,要让使用屏幕阅读器和其他辅助工具的人都能在页面中自由导航。兼容HTML5的无障碍工具可以为残疾人士提供更好的上网体验。(仅举一个例子,有了<nav>元素,屏幕阅读器就能够迅速返回导航区,进而找到网站的链接。)

提示 要了解针对Web无障碍性的最佳实践,可以访问WAI(Web Accessibility Initiative,Web 无障碍倡议)的网站:www.w3.org/WAI。或者,要了解通过屏幕阅读器上网是一种什么样的感觉(同时理解为什么标题要排列适当),可以看看YouTube的这段视频: http://tinyurl.com/6bu4pe

  • 搜索引擎优化。像谷歌这样的搜索引擎,会使用强大的搜索机器人(search bot),这些搜索机器人自动在Web中爬行并获取每一个网页。然后扫描网页内容并将它们索引到搜索数据库中。如果谷歌能够更好地理解你的站点,那搜索者的查询就会越容易与你的内容匹配,因而你的网站列在搜索结果中的可能性也就越大。搜索机器人已经在检查一些HTML5的语义元素了,这样可以收集到它们索引的页面的更多信息。

  • 未来的功能。新浏览器和Web编辑工具一定会利用语义元素。比如,浏览器可以提供一个页面的内容纲要,以方便访客跳转到页面中适当的区块。(事实上,Chrome已经提供了一个显示页面纲要的插件,详见2.5.1节。)类似地,网页设计工具也能包含一些方便你构建或编辑导航菜单的功能,而方法就是组织你放在<nav>区块中的内容。

最关键的问题在于,如果你正确地使用了语义元素,就能够创建更加清晰的页面结构,就能够适应未来的浏览器和Web设计工具的发展趋势。而如果你还是抱着原来写HTML标记的老习惯不放,那就要跟未来擦肩而过了。

2.2 改造传统的 HTML 页面

要了解和熟悉新的语义元素(包括学习如何使用它们来构造页面),最好的方式莫过于拿一个经典的HTML文档作例子,然后把HTML5的一些新鲜营养充实进去。图2-1是我们要改造的第一个页面。这个页面很简单,只包含一篇文章,当然对于其他内容(如博客、产品说明或简短的新闻报道)也完全没有问题。

提示 访问http://prosetech.com/html5,可以查看或下载图2-1中的示例页面以及本章所有的示例页面。如果你想从头开始做,那就选择ApocalypsePage_Original.html,如果想直接查看使用HTML5改造之后的结果,请选择ApocalypsePage_Revised.html。

2.2.1 构造页面的老办法

要生成图2-1所示的页面,有很多种构造方法。让人高兴的是,这个示例页面使用的是HTML最佳实践,因此没有任何通过标记来进行格式化的痕迹。没有粗体或斜体元素,没有嵌入的样式,当然更没有土得掉渣的<font>之类的东西。总之,这是一个格式非常规范的页面,所有样式均来自外部样式表。

图2-1:一个普通的HTML页面,具有类似文档的页面结构,其中的格式来自一个外部样式表

以下是从页面中摘出的一段标记,代码中加粗的地方表明应用了样式:

  <div class="Header">
    <h1>How the World Could End</h1>
    <p class="Teaser">Scenarios that spell the end of life as we know it</p>
    <p class="Byline">by Ray N. Carnation</p>
</div>

  <div class="Content">
    <p><span class="LeadIn">Right now</span>, you're probably ...</p>
    <p>...</p>

    <h2>Mayan Doomsday</h2>
    <p>Skeptics suggest ...</p>
  ...
</div>

  <div class="Footer">
    <p class="Disclaimer">These apocalyptic predictions ...</p>
    <p>
      <a href="AboutUs.html">About Us</a>
      ...
    </p>
    <p>Copyright © 2014</p>
</div>

代码中的省略号是怎么回事

本书不可能把每个示例的所有标记都印出来,除非把它扩充到12 000页,再毁掉一片成材林。不过,这些代码能够展示出页面的基本结构,以及所有重要的元素。为此,代码中使用了省略号(…),用以表示省略未印刷出来的内容。

例如,就拿这段代码来说,其中包含了图2-2所示页面主体中的所有内容,只不过省略了一些包含文字的段落、Manyan Doomsday后面的条目以及页脚中的一些链接。如果你想仔细观察页面中的每一处细节,当然没有问题,就在本书试验站点(http://prosetech.com/html5)查看示例文件即可。

在一个(像这个一样的)编写规范的传统HTML页面中,通过使用<div><span>元素,已经把大部分工作移交给了样式表。通过<span>可以为处在其他元素中的少量文本添加样式,而通过<div>不仅可以为整个内容区块添加样式,还可以构建起整个页面的结构(见图2-2)。

图2-2:通过<div>元素把页面分隔为三个逻辑区块:顶部的页眉、中部的内容和底部的页脚

这个例子中的样式表比较简单。整个页面的最大宽度设置为800像素,避免文本在宽屏显示器上显示得过长。页眉位于一个带蓝色边框的盒子中,内容区的两侧都添加了内边距,而页脚在整个页面底部居中。

因为使用了<div>元素,所以添加样式很容易。比如,样式表ApocalypsePage_Original.css使用下列规则为页眉及其中内容添加样式。

/*为<div>添加样式,使其具有页眉的外观(蓝色带边框)*/
.Header {
  background-color: #7695FE;
  border: thin #336699 solid;
  padding: 10px;
  margin: 10px;
  text-align: center;
}

/*为页眉中的<h1>添加样式(这是文章的标题)*/
.Header h1 {
  margin: 0px;
  color: white;
  font-size: xx-large;
}

/*为页眉中的子标题添加样式*/
.Header .Teaser {
  margin: 0px;
  font-weight: bold;
}

/*为页眉中的署名行添加样式*/
.Header .Byline {
  font-style: italic;
  font-size: small;
  margin: 0px;
}

你可能注意到了,这些规则有效利用了上下文选择符(见A.3.3节)。比如,用选择符.Header h1选择了页眉区域中的所有<h1>元素。

提示 附录A在介绍CSS时也用到了这个例子。如果你想知道应用给这个页面的所有样式规则,可以翻到A.4节。

2.2.2 使用HTML5 构造页面

<div>目前依旧是Web设计的必备元素,它是一个直观、多用途的容器,可以通过它为页面中的任何区块应用样式。但<div>的问题在于,它本身不反映与页面相关的任何信息。在你(或浏览器、设计工具、屏幕阅读器、搜索机器人)遇到一个<div>元素时,你知道它是页面中独立的一个区块,可是你不知道那个区块的意图。

要通过HTML5改进这种情况,可以把<div>替换成更具有描述性的语义元素。这些语义元素的行为与<div>元素类似:它们仅包含一组标记,除此之外没有其他作用,可以将它作为“格式挂钩”来为页面应用样式。不过,除此之外,它们还会为页面添加一点语义。

下面的代码是在图2-1所示页面基础进行了简单修改之后的结果,删除了两个<div>元素,但添加了两个HTML5的语义元素:<header><footer>

<header class="Header">
  <h1>How the World Could End</h1>
  <p class="Teaser">Scenarios that spell the end of life as we know it</p>
  <p class="Byline">by Ray N. Carnation</p>
</header>

<div class="Content">
  <p><span class="LeadIn">Right now</span>, you're probably ...</p>
  <p>...</p>

  <h2>Mayan Doomsday</h2>
  <p>Skeptics suggest ...</p>
  ...
</div>

<footer class="Footer">
  <p class="Disclaimer">These apocalyptic predictions ...</p>
  <p>
    <a href="AboutUs.html">About Us</a>
    ...
  </p>
  <p>Copyright © 2014</p>
</footer>

在这里,<header><footer>元素替代了原来的<div>元素。如果你在修改一个大型网站,可以考虑用HTML5中相应的语义元素来包装已有的<div>元素。

可能你已经注意到了,这个例子里的<header><footer>元素仍然使用了类名。这样做的目的就是不用修改原来的样式表。由于类名不变,所以原来应用到<div>元素的样式规则,可以应用给现在的<header><footer>元素。

不管怎么说,这里的类名还是有点多余。如果你想把它们都删掉,变成这样:

<header>
  <h1>How the World Could End</h1>
  <p class="Teaser">Scenarios that spell the end of life as we know it</p>
  <p class="Byline">by Ray N. Carnation</p>
</header>

那就得修改样式表规则,直接通过元素名来应用样式。对于当前页面,这样做没有问题,因为其中只有一个<header>和一个<footer>元素。

下面是修改之后的为<header>及其包含的所有元素应用样式的规则:

/*为<header>添加样式,使其具有页眉的外观(蓝色带边框)*/
header {
  ...
}

/*为<header>中的<h1>添加样式(这是文章的标题)*/
header h1 {
  ...
}

/*为<header>中的子标题添加样式*/
header .Teaser {
  ...
}

/*为<header>中的署名行添加样式*/
header .Byline {
  ...
}

这两种应用样式的方式会得到相同的结果。正如HTML5中的很多设计问题一样,可能需要充分地讨论,但到底该怎么做,没有硬性规定。

此时,也许你会问:为什么内容部分的<div>元素还保留着呢?这样没有问题,因为HTML5页面经常会混合各种语义元素和更通用的<div>容器。HTML5没有“content”元素,所以仍然可以使用<div>元素。

注意 这个网页在IE9之前的Internet Explorer中无法正确显示。为解决这个问题,可以参考2.3节的有关讨论。不过接下来,还是让我们再多接触几个能够增强页面的语义元素吧。

最后,还有一个元素有必要用在示例页面中。那就是HTML5的<article>元素,这个元素表示一个完整的、自成一体的内容块,比如博客文章或新闻报道。<article>元素应该包含所有相关的内容,包括标题、作者署名以及正文。添加了<article>元素之后的页面结构就变成如下所示:

<article>
  <header>
    <h1>How the World Could End</h1>
    ...
  </header>

  <div class="Content">
    <p><span class="LeadIn">Right now</span>, you're probably ...</p>
    <p>...</p>
    <h2>Mayan Doomsday</h2>
    <p>Skeptics suggest ...</p>
    ...
  </div>
</article>

<footer>
  <p class="Disclaimer">These apocalyptic predictions ...</p>
  ...
</footer>

图2-3是最终的页面结构示意图。

图2-3:重新设计之后,页面中使用了三个新的HTML5语义元素。对于原来的页面结构,我们可以理解为:“这是一个包含三个区块的页面。”而对于新的页面结构,可以这样想:“这是一篇包含文头和页脚的文章。”

尽管此时的页面在浏览器中看起来还是一样的,但后台已经潜伏了一些额外的信息。此时,如果正好一个搜索机器人造访你的网站,停留在这个页面上,那它就能迅速找到页面的内容(通过<article>元素)以及该内容的标题(通过<header>元素)。至于页脚,它就不会太在意了。

注意 有时候,需要把一篇文章拆开,分几个页面来显示。目前关于这个问题的处理方案,就是把文章的每一部分都放在它自己的<article>元素中——即使内容并不完整,也不是自成一体的。在实际使用语义元素的时候,语义元素与页面表现之间经常会发生冲突,这只是一个典型的例子。

2.2.3 用<figure>添加插图

很多页面中都包含图片。但是,插图(figure)与图片的概念还不完全一样。HTML5规范建议我们把插图想象成一本书中的附图;换句话说,插图虽然独立于文本,但文本中会提到它。

一般来说,插图应该是浮动的;换句话说,应该把它放在相关文本旁边的一个比较近便的位置上,而不要把它们锁定在特定的词或元素旁边。而且,插图通常还会有与之相伴的浮动图题。

下面是给这篇启示录般的文章添加插图的HTML标记。其中也包含正好在它前面和后面的两个段落,这样你就能知道插图在标记中的确切位置了。

<p><span class="LeadIn">Right now</span>, you're probably ...</p>
<div class="FloatFigure">

  <img src="human_skull.jpg" alt="Human skull">
  <p>Will you be the last person standing if one of these apocalyptic
  scenarios plays out?</p>
</div>

<p>But don't get too smug ...</p>

光有这些标记还不行,必须还得有相应的样式表规则,才能把插图定位到适当的位置(同时添加外边距、控制图题文本的格式,当然你也可以自己给它添加一个边框)。下面就是本书给出的样式规则:

/*为插图应用样式*/
.FloatFigure {
  float: left;
  margin-left: 0px;
  margin-top: 0px;
  margin-right: 20px;
  margin-bottom: 0px;
}

/*为图题应用样式*/
.FloatFigure p {
  max-width: 200px;
  font-size: small;
  font-style: italic;
  margin-bottom: 5px;
}

图2-4展示了目前这个示例页面的外观。

图2-4:现在,我们通过插图美化了文本。在标记中,插图恰好在第一段文本之后,因此它会浮动到后面文本的左侧。注意一下图题文本的宽度,我们通过限制这个宽度,让图题内容显示很充实、很优雅

如果你以前也是这样为内容添加插图的,那在听说HTML5专门为你量身打造了一个新的语义元素,一定会高兴得合不拢嘴。没错,在这里可以不再用那个乏味的<div>了,因为现在有了一个专门的<figure>元素。那么图题呢?图题可以放在<figure>中的<figcaption>元素里:

<figure class="FloatFigure">
   <img src="human_skull.jpg" alt="Human skull">
   <figcaption>Will you be the last person standing if one of these
   apocalyptic scenarios plays out?</figcaption>
</figure>

当然,给插图和图题应用什么样式,把它们放在什么位置上,还是由你说了算。对这个例子来说,你得修改样式规则的选择符,才能重新选中图题文本。现在使用的是.FloatFigure p,而修改之后应该是.FloatFigure figcaption

提示 在这个例子中,<figure>元素由于有一个类名(FloatFigure),所以仍然会被应用样式,这与元素名无关。使用类名是因为我们要为不同的插图应用不同的样式。比如,可以让有的插图靠左浮动,而让有的插图靠右浮动,有的插图还要应用不同的外边距或图题格式,等等。为了保留这种灵活性,还是有必要继续通过类来为插图应用样式。

打开浏览器看一下,插图还是那样。但不同的是标注插图的标记现在的含义已经非常明确了。(顺便提个醒,<figcaption>元素不是只能包含文本——任何HTML元素都可以,比如链接、小图标等。)

最后,有必要再说一件事。因为图题中经常就包含了对图片的完整说明,所以alt文本就显得有点多余了。这种情况下,可以把<img>元素中的alt属性删除:

<figure class="FloatFigure">
   <img src="human_skull.jpg">
   <figcaption>A human skull lies on the sand</figcaption>
</figure>

这里要小心的是,不能把alt文本设成空字符串。因为这就意味着你的图片纯粹是装饰用的,屏幕阅读器会忽略不读。

2.2.4 用<aside>添加附注

新的<aside>元素表示与它周围的文本没有密切关系的内容。这就是说,你可以像在印刷品中使用附注栏一样使用<aside>元素,可以通过它介绍另一个相关的话题,或者对主文档中提出的某个观点进行解释。(比如,可以直接翻到本节末尾的附注栏。)另外,也可以用<aside>来盛放广告、相关内容链接,甚至如图2-5所示的醒目引文(pull quote)。

图2-5:醒目引文也是从印刷行业中借用的技术,用于吸引读者注意力,突出重要的内容

当然,使用熟悉的<div>元素也可以创造这种效果,但用<aside>元素包装同样的内容,可以让标记更富有意义:

<p>... (in a suitably robotic voice) "Who's your daddy now?"</p>

<aside class="PullQuote">
  <img src="quotes_start.png" alt="Quote">
  We don't know how the universe started, so we can't be sure it won't
  just end, maybe today.
  <img src="quotes_end.png" alt="End quote">
</aside>

<h2>Unexplained Singularity</h2>

这一次,样式表把醒目引文浮动到了右边。为满足你的好奇心,下面给出了相应的样式:

.PullQuote {
  float: right;
  max-width: 300px;
  border-top: thin black solid;
  border-bottom: thick black solid;
  font-size: 30px;
  line-height: 130%;
  font-style: italic;
  padding-top: 5px;
  padding-bottom: 5px;
  margin-left: 15px;
  margin-bottom: 10px;
}

.PullQuote img {
  vertical-align: bottom;
}

语义元素是怎么来的

在发明HTML5之前,其发明者花了很长时间研究已有的网页。他们不是光浏览自己喜欢看的站点,还研读了谷歌对十亿个网页的统计信息。(如果你对这个出色的研究感兴趣,可以看看这里:https://developers.google.com/webmasters/state-of-the-web/。)

谷歌公布的这个调查分析并列出了Web作者在自己网页中使用的类名。谷歌的目的是想告诉大家,你们使用的类名可能与匹配的元素的用途相悖,从而为大家构造网页提供有价值的参考。比如,要是所有人都给一个<div>元素指定名为header的类,那么就可以推断出大家都把页眉内容放在网页的顶部。

谷歌发现的最重要的一个现象,就是大量的网页根本不使用类名(甚至连样式表都没有)。然后,他们汇编了一组最常用的类名,包括footerheadertitlemenunav,分别对应着HTML5中的<footer><header><nav>等新语义元素。另外一些由其他人建议但尚未创造出来的语义元素有searchcopyright等。

换句话说,Web页面拥有一些共性的东西,比如页面都有页眉、页脚、侧边栏和导航菜单。只不过大家在区分这些构造时采用的方式多多少少有点不一致。基于这个认识,从人们普遍的做法中提取出相应的语义,据以为HTML语言添加一些新元素,也就成了自然而然的事了。这就是HTML5中语义元素的来历。

2.3 浏览器对语义元素的支持情况

到目前为止,我们做练习做得还是很开心的。不过,这个结构良好的页面如果在旧版本浏览器里没法看,那用处可就不大了。

所幸的是,HTML5的这些语义元素已经基本得到了所有现代浏览器的支持。就算你想找到一个不支持它们的Chrome、Firefox、Safari或Opera的版本,都不太可能。最大的绊脚石还是IE9之前的Internet Explorer,包括仍然占很大比例的IE8。

幸运的是,语义元素还是一个比较容易弥补的功能。毕竟,语义元素本身什么也不做,要支持它们,只要让浏览器把它们当做普通的<div>元素就行了。为此,我们要做的就是像接下来几节所说的,为它们添加点样式规则。之后就可以得到超级可靠的语义元素,即使用10年前的老古董浏览器来看,也不是问题了。

注意 如果你使用了Modernizr(见1.6.7节),那你的页面会自动完成语义元素的修补工作。那么接下来几节的内容你就可以不看了。如果你没有使用Modernizr,或者你很想知道怎么完成修补工作,那请继续阅读。

2.3.1 为语义元素添加样式

浏览器在遇到不认识的元素时,会把它们当成内联(inline)元素。大多数HTML5语义元素(包括本章已经介绍的这些,但除<time>之外)都是块级元素,也就是需要在单独一行上来呈现它们,同时在它们与前后元素之间各添加一些空间。

不认识HTML5语义元素的浏览器不知道应该把它们显示为块级元素,所以很可能会把它们都挤到一起。为解决这个问题,只要在样式表中添加一条“超级规则”即可。下面就是一条为9个HTML5元素应用块级显示格式的规则:

article, aside, figure, figcaption, footer, header, main, nav, section,
summary {
  display: block;
}

这条规则对于能够识别HTML5元素的浏览器没有作用,因为它们的display属性已经被默认设成了block。而且这条规则也不影响我们已经为这些元素应用的样式。那些样式照样可以添加到它们身上。

2.3.2 使用HTML5“垫片”

对于大多数浏览器而言,上一节介绍的技术可以解决兼容问题。但这里的“大多数”并不包括IE8及更早的版本。换句话说,对于较早版本的IE,还要面临一个挑战:它们会拒绝给无法识别的元素应用样式。好在,有一个变通方案:通过JavaScript创建新元素,就可以骗过IE,让它识别外来元素。比如,下面的脚本可以让IE识别并为<header>元素应用样式:

<script>
  document.createElement('header')
</script>

实际上,你不用自己亲手写这些代码,因为已经有人为你写好了,只要拿过来用就可以了。要使用这个脚本,只要在页面的<head>区块中引用它即可,就像这样:

<head>
  <title>...</title>
  <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
  ...
<head>

这行代码会从html5shim.googlecode.com这个Web服务器上取得脚本,然后在浏览器处理页面其余部分之前运行。这个脚本使用前面描述的JavaScript代码创建所有的新HTML5元素,然后还会为它们动态应用上一节提到的样式,确保新元素能正确地显示为块元素。现在,剩下的事儿就是使用这些元素,并为它们应用你自己的样式。

对了,刚才忘说了,前面的html5.js脚本应该是有条件执行的——只在你使用旧版本Internet Explorer的情况下才会执行。为了避免不必要地加载JavaScript文件,可以像下面这样把引用脚本的代码放在IE的条件注释中:

<!--[if lt IE 9]>
  <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->

这样,其他浏览器(IE9及更高版本)就会忽略这行脚本,为你的页面节省数毫秒的加载时间。

提示 前面的例子直接使用了来自谷歌代码托管站点的垫片脚本。你也可以把它下载下来,地址为http://tinyurl.com/the-shiv。下载后放到本地目录里,改一下页面中引用这个脚本的地址即可。最后,还要提醒你,如果你是在本地计算机上测试网页(而不是上传到服务器),Internet Explorer会自动将页面置为受限模式。意思就是,你会在页面顶部看到臭名昭著的IE安全提示条,告诉你Internet Explorer已经禁用了其中的所有脚本,包括HTML5垫片脚本。要想正常测试,必须单击该安全提示条,选择允许活动的内容。

如果你把页面上传到网站中,就没有这个问题了,不过这无疑会增加测试的工作量。解决方案呢?就是在页面开头添加“Web标志”,详见1.3.5节。

2.3.3 Modernizr:一站式解决方案

要解决为语义元素应用样式的问题,还有一个方案:使用Modernizr(参见1.6.7节)。Modernizr内置了HTML5垫片脚本,因此会自动替你解决上述问题,不用你再使用html5.js或者添加什么样式规则了。因此,如果你已经在用Modernizr检测功能了,那么要考虑的就只有怎么使用语义元素了。

2.4 使用语义元素设计站点

在一个简单、类似文档的页面中应用语义元素相对容易。如果是把它们应用到整个站点也没有任何困难,但必须面对一系列新问题。因为HTML5还是一块未被开垦的处女地,很少有约定俗成的惯例(但却有一大堆合情合理的争议)。这样说吧,假设你准备从两种标记方案中选择一种,HTML5标准会说它们都是完全可以接受的,至于哪个方案最适合你的内容,你自己说了算。

图2-6展示了我们接下来将要设计的一个更有创造性的作品。

图2-6:这里,之前仅有一页的文章页面已经变成了一个完整的基于内容的站点。站点的页眉横跨上方,内容位居其下,而左侧的导航条提供了导航控件、About Us和一张图片广告

2.4.1 理解<header>

对于<header>元素来说,有两种使用方式,但差别并不大。一种是用它标注内容的标题,另一种是用它标注网页的页眉。有时候,这两种用途是重叠的(比如图2-1中那个单页文章的例子)。但有时候,你的网页里不仅要用<header>标注页眉,还要用它去标注很多内容的标题。图2-6所示的例子就是这种情况。

但有时候到底该不该用<header>并不十分明确,因为要标注的内容区块的角色变化会影响最终的决策。如果你处理的是内容,那么除非必要,一般不必使用<header>。只有在内容标题还附带了其他信息的情况下,才有必要考虑<header>。也就是说,其中包含标题、概要、发表日期、作者署名、图片或子主题链接等很多内容,例如:

<header>
   <h1>How the World Could End</h1>
   <p class="Tagline">Scenarios that spell the end of life as we know it</p>
   <p class="Byline">by Ray N. Carnation</p>
</header>

不过,在为网站创建页眉的时候,人们多数会直接考虑<header>元素,即便这个页眉就是一个CSS控制的长盒子,里面啥都没有。毕竟页眉是网站的一个核心组件,谁知道哪天你要往里面塞点什么东西呢!

结论如下:网页中可以包含多个<header>元素(通常也应该如此),即使相应的区块在页面中的角色不一样。

把网页变成网站

图2-6展示了一个虚构的网站中的一个页面。

在真实的网站中,可能几十个甚至更多个页面都会有相同的布局(以及相同的侧边栏)。访客点击页面的链接后,唯一变化的地方就是主页面中的内容——也就是这里的文章。

HTML5并没有什么魔法,它不会让你的网页自动变成网站。换句话说,你还要靠如下所示的以前开发网站的技术和技巧。

  • 服务器端框架。其实背后的思想都很简单:在浏览器请求某个页面时,Web服务器临时将页面的各个部分组装起来,包括公共的元素(如导航条)和内容。这是目前最常用的一种技术,也是构建大型、专业网站的必由之路。以不同方式实现这种手段的技术不计其数,包括很早就出现的服务器端包含功能,一些富Web应用平台(如ASP.NET和PHP),还有内容管理系统(如Drupal和WordPress)。

  • 页面模板。Dreamweaver、Expression Web等功能强大的网页编辑器中就有页面模板功能。模板就是一个定义了页面结构并且包含页面中会重复出现的内容(像页眉和侧边栏)的页面。有了模板,就可以利用它来创建网站的所有页面。最关键的是,更新模板之后,网站编辑器会自动更新使用该模板的所有页面。

图2-6所示的启示录网站用一个<header>元素作为站点的页眉,用另一个<header>元素作为文档的标题区。作为页眉的<header>中有一张横幅图片,图片中的文本也是由图片编辑器生成的:

<header class="SiteHeader">
  <img src="site_logo.png" alt="Apocalypse Today">
  <h1 style="display:none">Apocalypse Today</h1>
</header>

在此,我们注意到页眉中还包含一个我们在页面中看不到的<h1>元素,其中的内容与图片中的文本内容相同。而一条内联样式隐藏了这个标题。

这个例子提出了一个明显的问题——为什么要添加一个你看不见的标题?原因其实不止一个。首先,<header>元素中都应该包含某个级别的标题,这样做仅仅是为了遵守HTML5的规定。其次,这样设计可以让使用屏幕阅读器的人能够无障碍地阅读,因为他们经常会从一个标题跳到另一个标题,而不会关注标题之间的内容。最后,这样就为页面建立了标题结构,而页面其他部分的标题都要依序选用。如果我们说,在站点的页眉中使用了<h1>元素后,你就应该给页面中其他的区块(如“Articles”和“About Us”)选用<h2>元素作标题,你可能觉得有点怪。要了解为什么这样设计,请参考下面的附注栏“站点的标题结构”。

注意 当然,简单地给页眉中添加一行文字比较省事。(而如果你喜欢一些新奇的字体,还可以考虑CSS3新的Web字体功能,详见6.4节。)但对于诸多把标题放在图片中的网页而言,隐藏标题同样也是个不错的办法。

 

站点的标题结构

一个页面中可以有多个一级标题吗?这样做到底好不好?

根据HTML的官方说法,一个页面中可以有任意多个一级标题。但是,很多网站开发人员更倾向于每个页面只使用一个一级标题,因为这样能保证网页的无障碍性。(因为使用屏幕阅读器的人在从一个二级标题跳到另一个二级标题的时候,有可能错过中间的一级标题。)也有不少网络维护人员认为,每个页面就应该只有一个一级标题,这个一级标题在整个网站中是独一无二的,可以明确地告诉搜索引擎网站中有什么内容。

图2-6中的例子采用的就是这种风格。站点顶部的标题“Apocalypse Today”是页面中唯一的<h1>元素。页面中其他的部分,如侧边栏中的Articles和About Us,使用的都是二级标题。文章的标题使用的也是二级标题。(额外做一点规划,可以让一级标题中也包含当前文章的信息——毕竟,这个标题是不可见的,如此一来可以让通过谷歌等搜索引擎搜索特定关键词的人也能看到这个页面。)

不过,除此之外还有一种风格,也同样是允许的。换句话说,可以在页面中每个主要部分都使用一级元素,比如侧边栏、文章等。

或者,也可以给网站一个一级标题,而把侧边栏的内容用二级标题标注(就跟眼下这个例子一样),但是给文章再应用一个一级标题。在HTML5中,这样没有问题,因为它的纲要系统允许这样。稍后在2.5.3节将会介绍,有些元素(包括<article>),是被当作一个独立的区块来处理的,独立的区块可以有自己不同的纲要。这样,诸如此类的独立区块完全可以重新建立标题级别,再从<h1>开始。(不过,HTML5也说从任何标题级别开始都挺好的。)

简言之,如何设计站点的标题结构是一个没有唯一答案的命题。不过,随着HTML5获得胜利并统治Web,好像多个<h1>的设计会越来越时髦。不过现在,很多开发人员为了让屏幕阅读器开心,仍然坚持只使用一个<h1>

2.4.2 用<nav>标注导航链接

这个启示录网站中最有意思的新功能就是左侧的侧边栏,其中包含网站的导航、其他信息和一张图片广告。(一般来说,广告位都是放一段JavaScript脚本,从类似Google AdSense等服务随机地提取广告。但我们这个例子就硬编码了一张图片,就算是一种替代吧。)

在传统的HTML网站中,你可能会把整个侧边栏都放到一个<div>中。而在HTML5时代,则应该主要使用两个针对性更强的元素:<aside><nav>

要说<aside>元素,倒是跟<header>元素有点像,哪里像呢?<aside>的含义也有一点细微的发散。可以用它来标注一段与正文相关的内容(2.2.5节正是这么做的),也可以用它表示页面中一个完全独立的区块——作为页面主要内容的陪衬。

<nav>元素则用于包装一组链接。这些链接可以指向当前页面中的主题,也可以指向网站中的其他页面。多数页面中都会包含多个<nav>区块。但并不是所有链接都需要<nav>区块——相反,<nav>通常只用于页面中最大最主要的导航区。例如,对于一组文章的链接(像图2-6那样的),绝对需要一个<nav>区块。可是,如果只是放在页面底部几个许可或联系信息的链接,那大可不必麻烦<nav>

明白了这两个元素的用途,接下来该付诸实践了。首先,再看一看图2-6中的侧边栏。然后,在一张纸上画一画,看你打算怎么用标记体现其中内容的结构。最后,再接着往下看,一块来找一个最佳方案。

事实上,如图2-7所示,至少有两个比较合理的方式来构造侧边栏。

图2-7:左:可以把整个侧边栏想象成一个导航区,在其中填入一些内容。这样,整个侧边栏可以放在一个<nav>中,其他内容可以使用<aside>(因为其中的内容与侧边栏的主要内容——链接无关)。右:或者,可以把整个侧边栏想象成一个独立的多用途的网页区块。这样,侧边栏就是一个<aside>,而其中有关导航的内容放在<nav>里面

这个启示录站点使用的是第二种方案(即图2-7中右侧的结构)。选择该方案主要是因为这里的侧边栏有多种用途,而没有哪一种用途是主要用途。不过,要是这里的导航又长又复杂(比如都用上了可折叠的菜单形式),只是后面跟着一小段内容,那第一种方案就更合适一些。

以下就是构成侧边栏的标记,包含三个区块:

<aside class="NavSidebar">
  <nav>
    <h2>Articles</h2>
    <ul>
      <li><a href="...">How The World Could End</a></li>
      <li><a href="...">Would Aliens Enslave or Eradicate Us?</a></li>
      ...
    </ul>
  </nav>

  <section>
    <h2>About Us</h2>
    <p>Apocalypse Today is a world leader in conspiracy theories ..."
    </p>
  </section>

  <div>
    <img src="ad.jpg" alt="Luckies cigarette ad: it's toasted">
  </div>
</aside>

看完这些代码,应该注意到如下关键点。

  • 标题(Articles和About Us)使用的是二级标题。这样,它们就自然位于网站的一级标题之下,从而方便屏幕阅读器无障碍地阅读标题。

  • 链接以<ul><li>元素组成的无序列表来标记。网站设计师普遍认为,处理一组链接的最佳方式,也是最无障碍的方式,就是使用列表。不过,你可能得通过样式表删除列表项默认的缩进(这个例子已经这样做了)和项目符号(本例没有项目符号)。

  • “About Us”包含在一个<section>元素中。这是因为没有合适的语义元素。<section>当然要比<div>更具体一点,它适合任何以标题开头的内容区块。假如有一个更具体的元素(例如,假设有一个<about>元素),那么这里就不会用<section>,可惜没有。

  • 图片广告放在一个<div>。如前所述,<section>元素只适合带标题的内容,而这里的图片区块没有标题。(而如果真有的话,比如“A Word from Our Sponsors”,那就该用<section>元素了。)从技术角度看,根本没有必要把图片还放在其他元素中。但有了<div>,区块之间的关系就更明确了,这样更容易分别为不同的区块应用样式,或者在必要时通过JavaScript分别操作它们。

实际上,还有一些细节,这个侧边栏里没有,但可能其他侧边栏里会有。比如,复杂的侧边栏可能会以<header><footer>作为开头和结尾,也有可能包含多个<nav>区块——存档文章链接一个、新闻报道链接一个、友情链接或相关站点链接一个,等等。有兴趣的话,读者可以自己找找一些有代表性的博客,其中的侧边栏往往包含很多区块,其中不少都是导航用的。

这里为<aside>标注的侧边栏应用样式的规则,与为传统的<div>标注的侧边栏应用样式的规则一样。它们都会把侧边栏摆放到正确的位置上,使用绝对定位,设置某些格式上的细节,如内边距、背景,等等:

aside.NavSidebar
{
  position: absolute;
  top: 179px;
  left: 0px;
  padding: 5px 15px 0px 15px;
  width: 203px;
  min-height: 1500px;
  background-color:#eee;
  font-size: small;
}

这条规则后面是一些上下文样式表规则,分别为侧边栏中的<h2><ul><li>以及<img>元素应用样式。(跟以前一样,可以从http://prosetech.com/html5下载示例代码,然后仔细研究一下其中的所有样式规则。)

注意 我们已经介绍了,<nav>通常会单独出现,有时候也会出现在<aside>中。其实,还有一个地方也经常可以看到它的身影:网页顶部的<header>元素中。

理解了这个侧边栏是如何构造的,也就容易理解它与整个页面布局的关系了,如图2-8所示。

图2-8:这里展示了启示录网页(图2-6)中用到的所有语义元素

使用<details><summary>的折叠框

你肯定在有的网页上见过可以折叠的区块:通过单击区块标题能够显示或隐藏其中的内容。折叠框是用JavaScript能够轻易实现的众多界面元素之一。只要在单击标题的时候,适当改变样式设置,隐藏内容:

var box = document.getElementById("myBox");
box.style.display = "none";

或者再把内容显示出来即可:

var box = document.getElementById("myBox");
box.style.display = "block";

有意思的是,HTML5还新添了两个语义元素,用于辅助将这种行为自动化。具体做法是把可以折叠的区块放在一个<details>元素中,而把标题放在一个<summary>元素中。最终结果类似如下这样:

<details>
 <summary>Section #1</summary>
 <p>If you can see this content, the section is expanded</p>
</details>

支持这两个元素的浏览器(目前只有Chrome支持)只会显示标题——可能还会带有视觉上的提示(比如在标题旁边放在一个小三角形图标)。然后,用户单击标题,再把完整的内容显示出来。不支持<details><summary>的浏览器则上来就会显示所有内容,用户也不能把内容折叠起来。

目前,业内对<details><summary>元素还有争议。很多Web开发人员认为它们并不是真正的语义元素,因为它们更倾向于视觉表现,而非逻辑结构。

我们的建议是最好不要使用<details><summary>元素,因为支持它们的浏览器太少了。虽然可以用JavaScript写一段脚本在不支持它们的浏览器中使用,但编写这种脚本不如你自己实现一个在任何浏览器中都可以折叠的方案,毕竟那样只要几行代码而已。

2.4.3 理解区块

如前所述,区块元素<section>是应该最后考虑的语义元素。如果有一个带标题的内容块,而其他语义元素都不合适,那么选择<section>通常比选择<div>更好一些。

那么通常应该在<section>元素中放什么呢?这跟你的看法有关,它可能是一个能够适合各种需求的灵活的工具,也可能是一个松松垮垮没有明确身份的怪物。之所以会有这么大的区别,主要是因为<section>在网页中可以扮演很多不同的角色。可以放在<section>中的内容有以下几种。

  • 与页面主体内容并列显示的小内容块,例如我们启示录网站中的About Us段落。

  • 独立性内容,但却不能用文章(<article>)来描述,比如客户的购物记录或产品清单。

  • 分组内容——例如,新闻站点中的一组文章。

  • 比较长的文档中的一部分。比如,在启示录网站的文章中,可以用它把每种世界末日的情形标注为一个独立的区块。有时候,这样使用区块是为了保证文档能有一个正确的纲要,而这正是下一节我们要介绍的内容。

前面列出的最后两项可能会令你觉得很不可思议。很多Web开发人员会觉得用一个元素既可以标注一篇文章中的一个片段,又可以标注整个一组文章,这伸缩性似乎有点大了。有人认为HTML5至少应该用两个不同的元素来对应这两种情况。但HTML5的创造者希望一方面保持简单(限制新元素的数量),另一方面也让新元素尽可能灵活且实用。

最后,还有一件事儿要考虑。<section>元素也会影响网页的纲要,也就是2.5节要讨论的主题。

2.4.4 理解<footer>

HTML5与内容丰富的“胖”<header>可谓天生一对。在<header>中不仅可以放副标题和作者署名,还可以添加图片、导航区块(使用<nav>元素),以及任何有必要放在页面顶部的内容。

奇怪的是,HTML5对<footer>元素可就不那么有人情味了。HTML5规定,只能在<footer>元素中放一些网站版权信息、作品来源、法律限制及链接之类的信息。不能在<footer>里面放太多链接、重要的内容或无关的内容,如广告、社交媒体按钮以及网站部件等。

这就提出了一个问题:如果你的网站需要一个“胖”<footer>怎么办?毕竟,“胖”页脚目前非常流行(见图2-9中的例子)。这些“胖”页脚经常会用到如下所示的一些花哨的技术。

  • 固定定位,这样就可以让页脚始终固定在浏览器窗口底部,无论访客如何滚动都无所谓(如图2-9中的例子所示)。

  • 关闭按钮,这样用户在看完页脚内容后,单击它们就可以腾出页面空间(如图2-9中的例子所示)。为实现这个功能,要使用一点JavaScript代码(与前一节附注栏中使用的代码相似),以便隐藏包含页脚的元素。

  • 部分透明的背景,这样就可以透过页脚看到内容。如果页脚正在宣布即时新闻或重要的免责声明,部分透明的背景很合适,通常与关闭按钮联用。

  • 动画,页脚在视图中弹出,或者滑入视图(例如,可以看看在http://www.nytimes.com上阅读到一篇文章最后时弹出的相关文章提示框)。

如果你的站点中包含这种页脚,就要作出选择。比较简单的办法是无视规定。这个办法并没有听起来那么可怕,因为其他网站的开发人员也在犯同样的错误。而随着时间推移,官方的规定也可能会放开,允许用<footer>包含奇特的页脚。可是,假如你现在不想违反标准的规定,那就得调整一下标记。好在调整标记不难。

图2-9:这个荒唐的“胖”页脚中包含不少多余的内容,比如一个奖项图片和一些社交媒体按钮。它使用了固定定位使自己一直显示在浏览器窗口底部,就像一个工具条。好在这个页脚有一个地方可以弥补它的缺点,那就是右上角的关闭按钮,单击该按钮就能让这个页脚从视野中消失

调整标记的关键在于从多余的内容中提取出标准的页脚来。在浏览器中,这些内容看起来还是一个页脚,但在标记中,其他内容都不包含在<footer>元素中。例如,以下就是图2-9中“胖”页脚的实际结构:

<div id="FatFooter">
  <!—"胖"页脚的内容 -->
  <img onclick="CloseBox()" src="close_icon.png" class="CloseButton">
  ...
  <footer>
    <!-- 标准页脚的内容 -->
    <p>The views expressed on this site do not ... </p>
  </footer>
</div>

最外围的<div>没有特殊含义,它只是负责把多余的内容和标准的页脚内容包装起来。同样,可以给它应用一些样式表规则,以便将其锁定在合适的位置上:

#FatFooter {
  position: fixed;
  bottom: 0px;
  height: 145px;
  width: 100%;
  background: #ECD672;
  border-top: thin solid black;
  font-size: small;
}

注意 在这个例子中,样式表规则是通过ID应用样式的(使用#FatFooter选择符),并没有使用类名(如.FatFooter选择符)。这是因为“胖”页脚本身已经有了唯一的ID,目的是为了方便JavaScript代码在用户单击关闭按钮时可以找到并隐藏它。这种情况下,在样式表中使用唯一的ID要比另外添加一个类名更可取。

当然,也可以把页脚中的其余内容放在一个<aside>元素中,从而清楚地表明其中的内容属于一个独立的区块,与页面中的其他内容无关。相应的标记结构类似如下所示:

<div id="FatFooter">
  <aside>
    <!—"胖"页脚的内容 -->
    <img onclick="CloseBox()" src="close_icon.png" class="CloseButton">
    ...
  </aside>

  <footer>
    <!-- 标准页脚的内容 -->
    <p>The views expressed on this site do not ... </p>
  </footer>
</div>

这里最重要的一点是没有把<footer>放到<aside>元素中。因为<footer>并不属于<aside>,而是整个网站的一部分。类似地,如果有一个<footer>属于某些内容,那么就应该将这个<footer>放在包含相应内容的元素中。

注意 正确使用HTML5语义元素的规则和指导方针还在变化。在HTML社区中,有关如何在大型、复杂站点中正确使用标记的话题,常常会引起激烈的争论。在此,我给大家一个建议:如果某个元素看起来不适合标注你的内容,那就不要用。当然,你也可以上网去讨论,很多超聪明的HTML大师会为你现身说法。(最好的一个去处就是http://html5doctor.com,在该网站大多数文章的评论中,都可以看到正在争论中的话题。)

2.4.5 使用<main>标识主要内容

HTML5还有一个经常被人忽视的<main>元素,用于标识网页的主要内容。比如,在前面的启示录网站上,主要内容就是整篇文章,不包含站点页眉、页脚和侧边栏。强烈建议大家在自己的网页中使用这个元素。

在启示录网站中,我们就用<main>包装了<article>

<!DOCTYPE html>
<html lang="en">
<head>
  ...
</head>

<body>
  <header>
      ...
  </header>
  <aside>
      ...
  </aside>

  <main>
    <article>
      ...
    </article>
  </main>
  <footer>
    ...
  </footer>
</body>
</html>

不能把<main>嵌套到<article>(或其他任何语义元素)里边。这是因为<main>元素的使命就是包裹页面中的主要内容,而非标识文档中某个重要的部分。换句话说,一个页面中只能有一个<main>元素。

乍一看好像<main>也没有大用处。可是它对屏幕阅读器很重要,有了它,屏幕阅读器就可以跳过那些次要的内容,比如页眉、导航菜单、广告和侧边栏,直达内容。我们这个例子中<main>紧挨着<article>,这不是必须的。在复杂些的页面中,比如包含多个<article>元素时,<main>就应该包含所有<article>,像这样:

<main>
  <article>
    ...
  </article>

  <article>
    ...
  </article>

  <article>
    ...
  </article>

  ...
</main>

很明显,每个<article>都包含自己的内容,而<main>包含所有文章。

就算页面中没有<article>元素,同样可以使用<main>元素。比如,页游或应用页面可以用<main>元素包裹用于创建游戏和应用的标记。总之一句话,就是<main>只应该包含主要内容,而不是上下左右的外部细节。

注意 <main>是一个相对新的元素,是在HTML5的升级版HTML 5.1(参见前言中的“什么时候可以使用HTML5”)中引入的。

2.5 HTML5 纲要

HTML5定义了一组规则,用于说明如何为网页创建文档纲要(document outline)。网页的纲要能够提供很多便利。例如,浏览器可以让你从纲要中的一处跳到另一处。设计工具可以让你通过在纲要视图中拖放来重排区块。搜索引擎可以使用纲要构建更好的页面预览,而屏幕阅读器获得的便利最大,通过使用纲要可以引导视力有障碍的用户在深度嵌套的区块和子区块中导航。

不过,这些情形还没有一项成为现实,因为除了下一节将要介绍的几个开发人员工具,今天几乎还没有谁在使用HTML5纲要。

注意 一个不影响页面在浏览器中的表现,也没有其他工具使用的功能很难让人兴奋。但是,通过评审网页(至少是网站中典型网页)的纲要来确保其结构合理,而且你也没有破坏HTML5的规则,这个想法还是很不错的。

2.5.1 如何查看纲要

要真正理解纲要,只需看一看你的网页生成的纲要是什么样子的。目前,还没有浏览器实现HTML5纲要(或者给你提供一种查看方式)。不过,倒是有几个工具填补了这个空白。

  • 在线HTML纲要生成器。访问http://gsnedders.html5.org/outliner/,告诉纲要生成器你想为哪个网页生成纲要。如同我们在1.4.2节使用的HTML5验证器一样,可以通过三种方式提交网页:从本地电脑中上传、提供URL或直接在文本框粘贴标记。

  • Chrome扩展。在Chrome浏览器中查看网页纲要时,可以使用h5o插件分析纲要。访问http://code.google.com/p/h5o安装该插件,然后在网上找开一个HTML5页面看一看(可惜的是,在写作本书时,h5o不能分析本地计算机中的文件)。然后浏览器地址栏中会出现一个纲要图标,单击该图标就会显示页面的结构(如图2-10所示)。h5o的页面中也提供了一个书签工具(bookmarklet)——可以添加到浏览器书签列表中的一小段JavaScript代码,通过它可以在Firefox和Internet Explorer中显示页面的纲要,但也时候也会出点小状况。

  • Opera扩展。Chrome的h5o扩展也有一个针对Opera开发的版本,安装地址在http://tinyurl.com/3k3ecdy

图2-10:在通过安装了h5o的Chrome浏览器访问HTML5网页时,地址栏中会出现一个纲要图标,单击它就会弹出一个包含整个页面纲要的小窗口

2.5.2 基本纲要

要知道自己网页的纲要是什么样子,可以想象把页面中的所有内容都剥离,只剩下编号的标题元素(<h1><h2><h3>等)中的文本。然后,根据它们在标记中的位置缩进标题,那么嵌套最深的标题在纲要中的缩进也最多。

以最初的还没有应用HTML5元素之前的启示录文章页面的标记为例:

<body>
  <div class="Header">
    <h1>How the World Could End</h1>
    ...
  </div>
  ...
  <h2>Mayan Doomsday</h2>
  ...
  <h2>Robot Takeover</h2>
  ...
  <h2>Unexplained Singularity</h2>
  ...
  <h2>Runaway Climate Change</h2>
  ...
  <h2>Global Epidemic</h2>
  ...
  <div class="Footer">
    ...
  </div>
</body>

这个简单的结构会生成如下所示的纲要:

1. How the World Could End

   1. Mayan Doomsday

   2. Robot Takeover

   3. Unexplained Singularity

   4. Runaway Climate Change

   5. Global Epidemic

两个级别的标题(<h1><h2>)就创建两级的纲要。这种对应关系与字处理软件中的纲要功能类似。比如,可以在微软Word 的文档结构图窗格中看到类似的纲要。

换一个例子,对于下面的标记:

<h1>Level-1 Heading</h1>
<h2>Level-2 Heading</h2>
<h2>Level-2 Heading</h2>
<h3>Level-3 Heading</h3>
<h2>Level-2 Heading</h2>

会生成如下所示的纲要:

1. 一级标题

   1. 二级标题

   2. 二级标题

      1. 三级标题

   3. 二级标题

同样,没有什么意外。

最后,纲要算法也很聪明,能够自动忽略跳过的级别。例如,如果你写的标记有点不太规范,从<h1>直接就跳到了<h3>

<h1>Level-1 Heading</h1>
<h2>Level-2 Heading</h2>
<h1>Level-1 Heading</h1>
<h3>Level-3 Heading</h3>
<h2>Level-2 Heading</h2>

那会得到如下纲要:

1. 一级标题

   1. 二级标题

2. 一级标题

   1. 三级标题

   2. 二级标题

这样,根据其文本中的位置,本来的三级标题与二级标题放在了同一层次上。表面上看,这与浏览器喜欢干的自动纠错类似,但实际上这样处理有特殊的原因。在某些情况下,网页可能是由很多独立的部分拼起来的——例如,可能会包含在其他站点上发布的一篇文章。此时,嵌入内容的标题级别很可能与网页其他部分不会完美地匹配。但由于纲要算法可以消除这些差异,这种问题自然也就不是问题了。

2.5.3 分块元素

分块元素(sectioning element)是指那些在页面中创建新的、嵌套纲要的元素。这些元素有<article><aside><nav><section>。要理解分块元素的作用,可以想象一个包含两个<article>元素的页面。因为<article>是一个分块元素,所以这个页面中(至少)有3个纲要:整个页面有一个纲要、每篇文章有一个嵌套的纲要。

为了进一步弄清楚到底是什么状况,我们来看一看用HTML5改造之后的启示录文章页面:

<body>
  <article>
    <header>
      <h1>How the World Could End</h1>
      ...
    </header>

    <div class="Content">
      ...
      <h2>Mayan Doomsday</h2>
      ...
      <h2>Robot Takeover</h2>
      ...
      <h2>Unexplained Singularity</h2>
      ...
      <h2>Runaway Climate Change</h2>
      ...
      <h2>Global Epidemic</h2>
      ...
    </div>
  </article>

  <footer>
    ...
  </footer>
</body>

把这些标记复制到http://gsnedders.html5.org/outliner中,可以看到下面的结果:

1. Untitled Section

   1. How the World Could End

      1. Mayan Doomsday

      2. Robot Takeover

      3. Unexplained Singularity

      4. Runaway Climate Change

      5. Global Epidemic

这个纲要开始于一个无标题的区块(Untitled Section),也就是最上层的<body>元素。然后,<article>元素开始一个新的嵌套的纲要,其中包含一个<h1>元素和几个<h2>元素。

有时候,Untitled Section意味着一个错误。尽管<aside><nav>元素可以不带标题,但<article><section>则万万不可。拿前面的例子来说,无标题的区块是页面中的主区块,属于<body>元素。因为页面只包含一个<article>,所以页面本身没有必要再单独带一个标题,出现这个Untitled Section也没有办法,你可以忽略它。

现在,再来看一个复杂一点的例子,比如带有导航侧边栏的启示录站点(参见2.4节)。把相应的标记放到纲要生成器中,可以得到如下结果:

1. Apocalypse Today

   1. Untitled Section

      1. Articles

      2. About Us

   2. How the World Could End

      1. Mayan Doomsday

      2. Robot Takeover

      3. Untitled Section

      4. Unexplained Singularity

      5. Runaway Climate Change

      6. Global Epidemic

这一次,标记中包含两个分块元素,因此就有两个嵌套的纲要:一个属于侧边栏,另一个属于文章。此外,也有两个无标题区块,但都是合乎规范的——第一个是侧边栏的<aside>元素,第二个是文章中醒目引文的<aside>元素。

注意 除了分块元素之外,还有一些元素被称作区块根(section root)。这些元素不是从已有纲要向下分支,而是产生自己的纲要,但不会出现在包含页面的主纲要视图中。比如包含网页内容的<body>元素就是一个区块根,这当然合理。但HTML5还把下列元素视为区块根:<blockquote><td><fieldset><figure><details>

 

分块元素对复杂页面的意义

分块对于联合(syndication)和聚合(aggregation)都有很大意义,这两种方式都是从一个页面中取得内容,然后注入到另一个页面的技术。

例如,设想有一个网页,包含一些文章的节选内容,而这些内容都来自另外一个网站。假设这个网页本身有很深的标题嵌套结构,而在这个嵌套结构的某个地方——比如在一个<h4>标题下面——有一篇从其他网站抓来的文章。

在传统的HTML中,我们希望抓来的文章中的一级标题使用<h5>元素,因为它被嵌套在<h4>下方。可是,这篇文章的结构本来是针对其他网站设计的,而原来的页面没有什么嵌套,因此其标题很可能从<h2>甚至从<h1>开始。虽然这不影响页面显示,但却打乱了标题层级,特别是对屏幕阅读器、搜索引擎以及其他页面处理工具,则会造成更大的困难。

而在HTML5中,这个页面根本不是问题。只要你把这篇文章嵌套在一个<article>元素中,那么被抓过来的内容就会变成它自己嵌套纲要的一部分。而这个纲要可以从任意级别的标题开始,几级标题都无所谓。真正重要的是标题在包含文档中的位置。因此,如果这个<article>元素排在<h4>后面,那么文章中的第一级标题从逻辑上就像<h5>一样,第二级标题从逻辑上就像<h6>一样,以此类推。

最后的结论是:HTML5有一个讲究逻辑的纲要机制,让组合文档变得更容易。在这种纲要机制下,标题的位置变得更加重要,而实际的级别则没有那么重要了。这样,可以免得你搬起石头砸到自己的脚。

2.5.4 解决一个纲要问题

到现在为止,你已经看到本章的示例,也看到了这些示例生成的纲要。而且,你看到的纲要也都非常符合规范。可是,有时候也会出现一个问题。比如,你创建了以下页面结构:

<body>
  <article>
    <h1>Natural Wonders to Visit Before You Die</h1>
    ...
    <h2>In North America</h2>
    ...
    <h3>The Grand Canyon</h3>
    ...
    <h3>Yellowstone National Park</h3>
    ...
    <h2>In the Rest of the World</h2>
    ...
    <aside>...</aside>
    ...
    <h3>Galapagos Islands</h3>
    ...
    <h3>The Swiss Alps</h3>
    ...
  </article>
</body>

然后,你觉得这个页面的纲要应该是这样的:

1. Untitled Section for the

   1. Natural Wonders to Visit Before You Die

      1. In North America

         1. The Grand Canyon

         2. Yellowstone National Park

      2. In the Rest of the World

      3. Untitled Section for the

目录

  • 版权声明
  • O'Reilly Media, Inc.介绍
  • 前言
  • 第一部分 现代标记
  • 第 1 章 HTML5 简介
  • 第 2 章 用语义元素构造网页
  • 第 3 章 编写更有意义的标记
  • 第 4 章 构建更好的 Web 表单
  • 第二部分 视频、图形和特效
  • 第 5 章 音频与视频
  • 第 6 章 美妙的 CSS3 字体和特效
  • 第 7 章 CSS3 与响应式 Web 设计
  • 第 8 章 基本 Canvas 绘图
  • 第 9 章 高级 Canvas 技术:交互性和动画
  • 第三部分 构建 Web 应用
  • 第 10 章 数据存储
  • 第 11 章 离线应用
  • 第 12 章 与 Web 服务器通信
  • 第 13 章 地理定位、Web Worker 和历史管理
  • 第四部分 附录
  • 附录 A CSS 基础
  • 附录 B JavaScript:页面的大脑