HTML5区块跟大纲算法

HTML5区块和大纲算法

原文链接:

  • Using HTML sections and outlines - Mozilla Developer Network
  • 每集HTML5+CSS3网页布局教程-2大纲算法

HTML5标准带来了几个带有标准语义的新元素来描述Web文档结构。本文会介绍这些元素,并且讨论如何用这些元素定义令人满意的文档大纲。


HTML4时代的文档结构

文档的结构(或者可以说在body标签之间的结构)是展示和表现web页面的基础。HTML4使用了区块(sections)和子区块(sub-sections)的概念来描述文档的结构。使用div元素来定义一个区块,并且使用标题元素(h1-h6)来定义这个区块的标题。它们之间的关系决定了web文档的结构和大纲。

下面的这些代码:

<div class="section" id="forest-elephants" >
  <h1>Forest elephants</h1>
  <p>In this section, we discuss the lesser known forest elephants.
    ...this section continues...
  <div class="subsection" id="forest-habitat" >
    <h2>Habitat</h2>
    <p>Forest elephants do not live in trees but among them.
     ...this subsection continues...
  </div>
</div>

可以提炼出如下的大纲:

 1. Forest elephants
   1.1 Habitat

定义一个大纲中的节点不一定非要使用div元素,其实,只要一个标题元素(h1-h6)就已经足够用来暗示一个节点了,所以这些标签:

<h1>Forest elephants</h1>
  <p>In this section, we discuss the lesser known forest elephants.
    ...this section continues...
  <h2>Habitat</h2>
  <p>Forest elephants do not live in trees but among them.
    ...this subsection continues...
  <h2>Diet</h2>
<h1>*n gerbils</h1>

提炼出了如下的大纲:

 2. Forest elephants
   1.1 Habitat
   1.2 Diet
 3. *n gerbils

(译注:这段代码没有使用任何div标签,大纲是根据标题元素——例中为h1和h2——来提炼的)


HTML5解决的问题

在HTML4中,文档结构的定义和大纲的算法非常简陋,这带来了不少的问题:

【问题1】用div元素来定义具有语义的区块的话,没有特定的class就没法自动生成大纲(“这个div是大纲的一部分,用来定义区块或者子区块的?”还是“它仅仅就是个div,为了方便使用CSS用来做样式的?”),换句话说,HTML4在“什么是区块、区块的范围怎么定义”这些问题上很不明确。页面是否能自动生成大纲非常重要,因为大多数屏幕阅读器(为有视力障碍人士提供的辅助阅读技术)就是根据文档大纲来规整它们将要展示给用户的信息。而在HTML5中,大纲算法不再必须使用div元素,取代div的是一个新的元素——section.

【问题2】多文档的融合是个难题:引入一个从别处采集来的子文档很可能会改变标题元素的等级,而HTML4正事根据这些标题元素的等级来提炼大纲的。HTML5引入了一系列全新的定义区块的元素(article, section, nav和aside),这些元素有这样的特性:不管它内部的标题元素(h1-h6)是什么级别,它总是离它最近的祖先区块的子节点。

译者例:

<body>
<h3>h3标题</h3>
<section>
    <h1>h1标题</h1>
    <p>从其他文档引入的section区块</p>
</section>
<div>
    <h2>h2标题</h2>
    <p>从其他文档引入的div区块</p>
</div>
</body>

上述代码提炼出的大纲如下:

1.h3标题
    1.1.h1标题
2.h2标题

可以看到,h1标题竟然成为了h3标题的子节点,这就是section元素的功劳了。因为不管它内部的标题元素是老大(h1)还是老六(h6),它都乖乖的成为离他最近的祖先节点(body)的子节点。再看div,虽然理论上应该也是body的子节点,但由于h2的级别高于h3(h3是body的标题),所以在大纲中竟和body变成了同级节点。

【问题3】在HTML4中,每个节点都是大纲的一部分。但web文档有时候并不是线性的。web文档有时可能会包含特殊的区块来承载信息,但这些信息并不属于主文档的一部分,比如广告和注释。HTML5引入了aside元素,该元素不会作为大纲的节点而成为大纲的一部分。

【问题4】同样的,在HTML4中,由于每个节点都是大纲的一部分,所以也没有适合的区块来承载logo、菜单、目录、版权信息和法律条款等这些信息,因为这些信息和web页面的内容无关,而是和web站点有关。为了解决该问题,HTML5同样引入了三个新元素:①用来承载链接(例如导航菜单和目录)的nav元素②用来承载web站点相关信息的header元素③用来承载web站点相关信息的footer元素。请注意header和footer和section不同,它们不会在大纲中出现,只负责语义性的描述一个区块(译注:有点类似div,但具有语义)。

总而言之,HTML5带来了更准确的区块和标题功能,这使得文档的可控性更强,而且更容易被浏览器使用,从而更好地提高用户体验。


HTML5的大纲算法

让我们来看看大纲算法是如何提炼区块和标题的。

body元素中所有元素都是节点。除了body元素定义的主节点,定义节点可以分为“显性定义的节点”和“隐性定义的节点”两种(以下下简称为“显性节点”和“隐性节点”)。

1.显性定义节点

显性节点使用<body>、<section>、<article>、<aside>和<nav>这些标签来定义。

在HTML5中,每个节点都有它自己的标题分级标准。所以即使是一个嵌套的区块也可以用h1作为标题。详见“2.定义标题”部分

例:

<section>
  <h1>Forest elephants</h1> 
  <section>
    <h1>Introduction</h1>
    <p>In this section, we discuss the lesser known forest elephants.</p>
  </section>
  <section>
    <h1>Habitat</h1>
    <p>Forest elephants do not live in trees but among them.</p>
  </section>
  <aside>
    <p>advertising block</p>
  </aside>
</section>
<footer>
  <p>(c) 2010 The Example company</p>
</footer>

这段代码中section定义了一个*区块,*区块中定义了三个子区块(两个section和一个aside)。这段代码可以提炼出如下的大纲:

1. Forest elephants
   1.1 Introduction
   1.2 Habitat
   1.3 Untitled Section

(译注:还记得吗?aside定义的节点也能出现在大纲中,但上例中并没有为aside定义标题,所以在大纲中出现了untitled section的字样)

2.定义标题

HTML的布局元素用来定义文档的结构,HTML的标题元素则用来给这些结构和这些结构所提炼的大纲赋予意义。

规则很简单:当前区块的第一个标题元素就是这个区块在大纲中节点的标题。

标题元素根据它元素名字里的数字来划分等级,其中h1等级最高,h6等级最低。标题元素等级只有在同一个区块中才有意义;决定大纲的是文档的区块结构,而不是标题元素的等级。举例来说,参考如下代码:

<section>
  <h1>Forest elephants</h1>    
  <p>In this section, we discuss the lesser known forest elephants. 
    ...this section continues...
  <section>
    <h2>Habitat</h2>  
    <p>Forest elephants do not live in trees but among them.
        ...this subsection continues...
  </section>
</section>
<section>
  <h3>*n gerbils</h3>
  <p>In this section, we discuss the famous *n gerbils. 
     ...this section continues...
</section>

这些代码提炼出如下大纲:

1. Forest elephants
   1.1 Habitat
2. *n gerbils

(译注:之所以h3元素和h1元素同级,是因为h3所属的区块和h1所属的区块同级,这就说明了决定大纲的是区块结构,而不是标题元素的等级)

请注意标题元素的等级是不重要的(上例中h1是第一个*的区块的标题,h2是子区块的标题,h3是第二个*区块的标题)。任何等级的标题都可以用在显性区块里,但并不推荐这样做。

3.隐性定义节点

在HTML5中,并不是只能用这些区块定义元素来定义大纲,考虑到兼容统治了web很长时间的HTML4,HTML5制订了不使用区块定义元素而使用标题元素来定义的节点方法,并称之为隐性定义节点。

在一个显性定义的节点中,第一个标题元素是该显性节点的标题,从第二个标题元素开始(包括第二个标题元素),之后的标题元素会定义新的节点,这些新的节点就是隐性定义的节点(因为并没有用到显性定义节点的元素)。

隐性节点有可能作为同级节点或子节点存在,这取决于定义它的标题级别。
如果定义它的标题级别低于之前的标题级别,那么它作为子节点存在。看看代码:

<section>
  <h1>Forest elephants</h1>  
  <p>In this section, we discuss the lesser known forest elephants.
    ...this section continues...
  <h3 class="implicit subsection">Habitat</h3>
  <p>Forest elephants do not live in trees but among them.
    ...this subsection continues...
</section>

提炼出下面的大纲:

1. Forest elephants
   1.1 Habitat (通过h3元素隐性定义)

如果定义它的标题级别和之前的标题级别相同,它将关闭之前的节点并隐性定义一个同级别的节点:

<section>
  <h1>Forest elephants</h1>  
  <p>In this section, we discuss the lesser known forest elephants.
    ...this section continues...
  <h1 class="implicit section">*n gerbils</h1>
  <p>*n gerbils are cute little mammals.
    ...this section continues...
</section>

提炼出下面的大纲:

1. Forest elephants
2. *n gerbils (通过h1元素隐性定义,同时关闭之前的区块)

如果定义它的标题级别高于之前的标题级别,它将关闭之前的节点并隐性定义一个同级别的节点:

<body>
  <h1>Mammals</h1>
  <h2>Whales</h2>
  <p>In this section, we discuss the swimming whales.
    ...this section continues...
  <section>
    <h3>Forest elephants</h3>  
    <p>In this section, we discuss the lesser known forest elephants.
      ...this section continues...
    <h3>*n gerbils</h3>
      <p>Hordes of gerbils have spread their range far beyond *.
         ...this subsection continues...
    <h2>Reptiles</h2>
      <p>Reptiles are animals with cold blood.
          ...this section continues...
  </section>
</body>

提炼出下面的大纲:

1. Mammals
   1.1 Whales (通过h2元素隐性定义)
   1.2 Forest elephants (通过section元素显性定义)
   1.3 *n gerbils (通过h3元素隐性定义,同时关闭之前的节点)
   1.4 Reptiles (通过h2元素隐性定义,同时关闭之前的节点)

这种大纲并不是稍微瞥一眼就能快速通过标题元素读懂的大纲。为了让你的大纲和HTML(对于人的)可读性更强,建议使用显性标签来定义或关闭节点,并且建议在区块嵌套时,标题元素的级别符合自然习惯。但是,HTML5手册并不强制要求这么做。如果你发现浏览器没有按照你的预期渲染大纲,检查看看是不是有一些节点被标题元素隐性声明的节点关闭了。

译者例 - 稍微复杂的大纲:
HTML5区块跟大纲算法
提炼出下面的大纲:

1.文档标题
    1.h3标题
        1.h5标题
        2.h4标题
            1.h5标题
    2.h3标题
    3.h1标题
        1.h2标题
            1.h3标题
        2.h2标题

分析:
HTML5区块跟大纲算法

3.根节点

在HTML中,一个有自己的大纲系统,但是,这些元素对于它们的祖先的大纲没有任何影响。Body元素是文档的逻辑根节点,也有一些元素引入外部的内容,比如blockquote, details, fieldset, figure和td.

举例来说:

<section>
  <h1>Forest elephants</h1> 
  <section>
    <h2>Introduction</h2>
    <p>In this section, we discuss the lesser known forest elephants</p>
  </section>
  <section>
    <h2>Habitat</h2>
    <p>Forest elephants do not live in trees but among them. Let's
       look what scientists are saying in "<cite>The Forest Elephant in Borneo</cite>":</p>
    <blockquote>
       <h1>Borneo</h1>
       <p>The forest element lives in Borneo...</p>
    </blockquote>
  </section>
</section>

上面的代码提炼出如下的大纲:

 1. Forest elephants
   1.1 Introduction
   1.2 Habitat

在section中的blockquote元素不显示在主大纲中,因为它是一个作为外部引用的、拥有独立内部大纲的根节点。(译注:事实上,所有的根节点元素都不会显示在主大纲中)

4.不属于主大纲的区块

HTML5中引入的两个新元素允许开发者定义一个区块,但这个区块不会在大纲中创建节点:

  1. HTML5的aside元素定义一个区块,这个区块属于文档的主元素,但不属于主文档流(比如注释或广告区域)。它有独自的大纲,但不属于主大纲。

  2. HTML5的nav元素定义一个用于承载导航链接的区块。一个文档中可以有好几个nav元素,比如一个用来存放页面内的链接(像是文章目录),一个用来存放站点的导航链接。这些链接并不属于主文档流和主大纲,而且一般不会被屏幕阅读器或其他辅助设备优先渲染。

5.头元素和尾元素

HTML5也引入了两个新的元素用来标记头部和尾部:

  1. HTML5的header元素定义页面的头部——通常包含logo、站点名称,也可能包含一个水平导航菜单。当然header也可以作为区块的头部,用来承载区块的标题、作者等。像article, section, aside和nav元素都可以有它自己的header.不过,你也不一定非要在每个页面或区块的都不放置这样一个元素。

  2. HTML5的footer元素定义页面的尾部——通常包含版权信息、法律声明,有时候还包含一些链接。当然footer也可以作为区块的尾部,可能用来承载区块里面内容的出版时间、版权信息等等。像atricle, section, aside和nav元素都可以有自己的footer.不过,你也不一定非要在每个页面或区块都放置这样一个元素。

Header和footer元素不会在大纲中创建新的节点,它们只用来标记页面中的区域。


总结

HTML5引入的新语义化元素将描述文档结构和大纲标准化。这为拥有HTML5浏览器而且需要大纲来帮助理解页面的人带来了极大的便利,比如需要使用辅助阅读技术的残障人士。这些新的语义化元素使用简单、副作用小,在非HTML5浏览器中也可以使用。



附加节:实际使用中div和section的区别

本小结引自集HTML5+CSS3网页布局教程-2大纲算法

1.何时使用div

div元素在html5之前是最常用的最流行的标签,但他本身是没有任何语义的,它只不过是用来布局页面和CSS样式以及JS调用。

  1. 如果是页面布局,且不是header、footer之类的专属区域,都应该使用div;
  2. 如果只是单纯的对一个段内容进行CSS样式定义,那么也应该使用div;
  3. 如果想对一段内容进行JS控制,那么也应该使用DIV;

2.何时使用section

在html5中,section标签并不是用来取代div的,他是具有语义的文档标签,表示一段文档中的章节,比如包含一个标题和一个段落,而大纲规范中,至少要包含一个标题。