浅谈 HTML5 的大纲算法(HTML5 Outliner)

写完这篇博客感觉 HTML5 的大纲算法就是大坑,很多地方的描述都是有所出入的,所以只能一切靠事实(实验)说话…

注:笔者在文末会介绍两种使 HTML 大纲可视化的方法,读者可以自行选择。

HTML4 的文档结构

文档结构,即 <body> 标记之间内容的语义结构,对呈现页面给用户是很重要的。HTML4 用文档中章节和子章节的概念去描述文档结构。一个章节由一个包含着标题元素(h1-h6)的div元素表示。这些html划分元素(HTML Dividing Elements)和标题元素(HTML Heading Elements)形成了文档的结构和纲要。

优秀的文档结构,不单单有助于搜索引擎的优化(SEO),更是能为借助于屏幕阅读器浏览网页的盲人(或弱视力)用户提供巨大帮助。

而正如上面讲的,在HTML5出现之前,HTML4便是通过 h1-h6 的标题元素来创建大纲。在一般情况下,只要合理正确的使用标题元素,的确可以为文档赋予一个良好结构的大纲。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div class="section">
<h1>HTML5 的文档节段和纲要</h1>
<p>HTML5新增了几个新元素使得开发者可以用标准语义去描述web文档的结构。</p>
<div class="subsection">
<h2>HTML4 的文档结构</h2>
<p>HTML4用文档中章节和子章节的概念去描述文档结构。</p>
<div class="subsubsection">
<h3>文档的结构和纲要</h3>
<p>划分元素(HTML Dividing Elements)和
标题元素(HTML Heading Elements)形成了文档的结构和纲要。</p>
</div>
</div>
</div>
<div class="section">
<h1>HTML5 的音频和视频</h1>
<div>

该代码形成了如下大纲:

section_1 outliner

上述代码对于每一个章节使用了一个包含着标题元素的 div 元素来表示,可 div 元素其实并不表示定义一个章节(在这里的作用是使文档结构化),事实上一个新的 HTML 标题元素(HTML Heading Element)的出现就意味着产生了新的章节。

也就是说上述代码可以改成这样:

1
2
3
4
5
6
7
8
<h1>HTML5 的文档节段和纲要</h1>
<p>HTML5新增了几个新元素使得开发者可以用标准语义去描述web文档的结构。</p>
<h2>HTML4 的文档结构</h2>
<p>HTML4用文档中章节和子章节的概念去描述文档结构。</p>
<h3>文档的结构和纲要</h3>
<p>这些html划分元素(HTML Dividing Elements)和
标题元素(HTML Heading Elements)形成了文档的结构和纲要。</p>
<h1>HTML5 的音频和视频</h1>

检查发现其大纲并没有变化:

section_2 outliner

看起来还不错(笑

然而,HTML 4 的文档结构定义和其隐含的非常粗糙的大纲算法造成了很多问题:

  1. 由于 HTML4 实际上是以标题元素(h1-h6)作为章节的划分,并且标题元素的级别是其划分主副的关键,这也导致了文档间的合并变得十分困难。假如你要往一个主文档里合并子文档,那么就必须改变子文档里标题元素的级别(诸如将h1改为h2之类…)才能使文档大纲保持下来。而 HTML5 新引入的元素(<article><section><nav><aside>) 总是距离其最近的祖先章节的子章节, 与子文档章节内部的标题没有关系。

  2. HTML4 中,所有的章节都是文档大纲中的一部分。但是文档并不总是这样,有些网站本身是聚合性质的,因此文档需要可以包含那些不属于大纲的章节,比如引用外来文档等。(HTML5 的 <blockquote>

  3. 同样,HTML4 的大纲算法, 没有办法产生与网站相关而不是与文档相关的节段,比如 logos,menus,目录或版权信息和法律声明。(HTML5 的 <header<footer>

可见,随着 HTML5 的应运而生,上述问题都在 HTML5 中得到了很好的解决。

HTML5 的大纲算法

Defining sections and headings(节段与标题)

<body> 元素定义了主节段,基于主节段,可以显式或隐式定义各个子节段的划分。显式定义的节段是通过<body>,  <section>,  <article>,  <aside>,  <nav> 这些标记中的内容。 (不包含 <header> 和 <footer>)

注:事实上 MDN 里的说法是包含了 <header><footer> 的,但经过其他文档的查阅以及自身实验,可以发现二者其实并不是节段元素。

HTML5 section 元素 (<section>) 表示文档中的一个区域(或节),比如,内容中的一个专题组。包括<section>,每种显式定义的节段一般都会包含一个标题(heading),通过是否包含标题(h1-h6)元素作为子节点来辨识每一个节段,其中,第一个 HTML 标题元素(<h1>, <h2>, <h3>, <h4>, <h5>, <h6>之一)定义了当前节段的标题。

值得注意的是,每个节段都可以有自己的标题结构,相关的标题级别只在节段中起作用。因此,即使是一个嵌套的 section 也能有 <h1>

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<body>
<section>
<h1>HTML5 的文档节段和纲要</h1>
<p>HTML5新增了几个新元素使得开发者可以用标准语义去描述web文档的结构。</p>
<section>
<h2>HTML4 的文档结构</h2>
<p>HTML4用文档中章节和子章节的概念去描述文档结构。</p>
<section>
文档的结构和纲要
</section>
</section>
</section>
<section>
<h1>HTML5 的音频和视频</h1>
</section>
</body>

生成大纲:

section_4 outliner

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<body>
<h1>HTML5 的大纲算法</h1>
<section>
<h1>HTML5 的文档节段和纲要</h1>
<p>HTML5新增了几个新元素使得开发者可以用标准语义去描述web文档的结构。</p>
<section>
<h1>HTML4 的文档结构</h1>
<p>HTML4用文档中章节和子章节的概念去描述文档结构。</p>
<section>
<h1>文档的结构和纲要</h1>
<p>这些html划分元素(HTML sectioniding Elements)和
标题元素(HTML Heading Elements)形成了文档的结构和纲要。</p>
</section>
</section>
</section>
<footer>
HTML5 的音频和视频
</footer>
</body>

生成大纲:

section_3 outliner

Implicit sectioning(隐式分节)

说是隐式分节,其实主要目的就是为了与 HTML4 保持兼容,之前我们提到,在 HTML4 中一个新的 HTML 标题元素(<h1> - <h6>)的出现就意味着产生了新的章节,而这个性质在 HTML5 中保留了下来 —— 当其不是父节段第一个标题时,该方式将定义一个新的隐式节段(在不需要分节元素的情况下)。

这种隐式定义节段的方式跟其在父节点中与之前标题的相对级别有关:

MDN中是这样说的

如果比之前的标题级别更低,那么在节段里开始新的隐式子节段;
如果与前面标题的级别相同,那么闭合前面的节段(可能是显式标记的节段!)并开始新的同一级别的隐式节段;
如果比之前标题的级别更高,那么关闭之前的节段并开始新的这个更高级别的隐式节段。

然而经过我自己的尝试发现跟其描述有所出入(特别是第三点),不知道是 MDN 文档的问题还是 程序 HTML5 Outliner 的问题(在尝试了几款其他 HTML5 Outliner 后倾向于是 MDN 的问题)。

我试了不少样例,现在重新总结如下:

在同一显式节段内,并且比较时不包括前面其余显式定义的子节段,如果当前标题级别

  • 如果当前标题级别比之前的标题级别更低,那么在前面节段(显式或隐式)里开始新的隐式子节段
  • 如果当前标题级别与前面标题的级别相同,那么闭合前面的节段(显式或隐式)并开始新的同一级别的隐式节段
  • 如果当前标题级别比之前标题的级别更高,那么闭合前面的节段(显式或隐式)并在当前所在显式节段内寻找小于等于自己的最高级别的标题,产生新的同一级别的隐式节段

可能有点绕…

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<body>
<h1>HTML5 的大纲算法</h1>
<section>
<h3>HTML5 的文档节段和纲要</h3>
<section>
<h2>HTML4 的文档结构</h2>
<!-- 当前标题级别比之前的标题级别更低 -->
<h3>HTML5 的音频和视频</h3>
</section>
<!-- 当前标题级别与前面标题的级别相同 -->
<h3>定义节段和标题</h3>
<section>
<h3>文档的结构和纲要</h3>
</section>
<!-- 当前标题级别比之前标题的级别更高 -->
<h1>隐式节段</h1>
</section>
</body>

生成大纲:

section_6 outliner

Sectioning roots(虚节根)

虚节根是一个HTML元素,这个元素可以拥有自己的大纲,但是元素内部的节段和标题对其祖先的大纲没有贡献。与文档的逻辑分节根<body>元素相比,这些元素经常在页面中引入外部内容:<blockquote>, <details>, <fieldset>, <figure> 和<td>。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<h1>HTML5 的大纲算法</h1>
<section>
<h1>HTML5 的文档节段和纲要</h1>
<p>HTML5新增了几个新元素使得开发者可以用标准语义去描述web文档的结构。</p>
<section>
<h1>HTML4 的文档结构</h1>
<p>HTML4用文档中章节和子章节的概念去描述文档结构。</p>
<section>
<h1>文档的结构和纲要</h1>
</section>
</section>
<blockquote>
<h1>MDN</h1>
<section>
<h1>Mozilla Foundation</h1>
</section>
</blockquote>
</section>
<section>
<h1>HTML5 的音频和视频</h1>
</section>

生成大纲:

section_7 outliner

显然,虽然 <blockquote> 里包含了 <section><h1> ,但在大纲中并无显示。

语义化

HTML5 定义了一个新标签 <main>,规定文档的主要内容。
<main> 元素中的内容对于文档来说应当是唯一的,在一个文档中,不能出现一个以上的 <main> 元素且<main> 元素不能是以下元素的后代:<article><aside><header><footer><nav>

  1. <article> 规定独立的自包含内容,一篇文章应有其自身的意义,应该有可能独立于站点的其余部分对其进行分发,比如论坛帖子、报纸文章、用户评论等。
  2. <aside> 定义其所处内容之外的内容,它的内容应该与附近的内容相关,就像解释栏或广告栏。
  3. <header> 定义了页面的头部,通常会包含 logo 和站点名称以及可能有的水平菜单。尽管名字是header,但是不一定是在页面的开始,比如可以包含在 <article> 的内部。
  4. <footer> 定义了页脚,通常会包含版权信息和法律声明以及一些其他链接。同样,其不一定是在页面的底部出现,也可以包含在 <article> 的内部。
  5. <nav> 定义的节段包含了很多导航links。文档中可以有好几个这样的元素,比如文档内部的链接,就像目录,和链接到其他站点的导航 links。

注:main 元素并不是一个节段,并不作为文档大纲的一部分。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<body>

<header>The Lawson Academy:
<nav>
<ul>
<li><a href="courses.html">Courses</a></li>
<li><a href="fees.html">Fees</a></li>
<li><a>Graduation</a></li>
</ul>
</nav>
</header>


<main>
<nav>
<ul>
<li><a href="#ceremony">Ceremony</a></li>
<li><a href="#graduates">Graduates</a></li>
<li><a href="#awards">Awards</a></li>
</ul>
</nav>

<h2 id="ceremony">Ceremony</h2>
<p>Opening Procession</p>
<p>Speech by Valedictorian</p>
<p>Speech by Class President</p>
<p>Presentation of Diplomas</p>
<p>Closing Speech by Headmaster</p>

<h2 id="graduates">Graduates</h2>
<ul>
<li>Eileen Williams</li>
<li>Andy Maseyk</li>
<li>Blanca Sainz Garcia</li>
<li>Clara Faulkner</li>
<li>Gez Lemon</li>
<li>Eloisa Faulkner</li>
</ul>

<h2 id="awards">Awards</h2>
<ul>
<li>Clara Faulkner</li>
<li>Eloisa Faulkner</li>
<li>Blanca Sainz Garcia</li>
</ul>

</main>

<footer> Copyright 2012 B.lawson</footer>

</body>

生成大纲:

section_9 outliner

安装 HTML5 Outliner

对于大纲的可视化,这里推荐两种办法。

一种是通过在线网址测试,在线网址功能繁多,支持上传 HTML 文件,填写 URL,以及粘贴 HTML 代码。

另一种方法是安装 Chrome 应用程序扩展,在应用商店搜索 HTML5 Outliner(Generates a navigable page outline with heading and sectioning elements.)并安装就可以了,功能比较单一,暂时只支持在线运行的网页。

总结

HTML5 的大纲算法以及其引入的新元素显然更有助于 HTML 的语义化,但鉴于由于有些用户代理并没有完全支持 HTML5 ,因此在现实中最好做到标题级别与节段嵌套级别相匹配,保证标题的层级正确,方便节段在多个文档中的重用。

另外,由于本篇博文是笔者查阅相关文献后独自完成,难免会有所纰漏或考虑欠妥的地方,欢迎大家指正,非常感谢!

参考文献

Using HTML sections and outlines(感觉有不少描述是错误的/不严谨的…)
4.3 Sections — HTML5
The HTML5 Document Outline

转载请注明出处:http://zhengboyang.com

如果您觉得这篇博文对您有所帮助,可以考虑请我吃颗糖哦!