纵观一篇 word 文档,一般都是通过章节来组织整个正文的内容,而构成正文的基本元素包括段落、列表、表格、超链接及嵌入式对象(如图片、视频、音频、文档)等。

通过这些基本元素的排列、组合、嵌套,便构成了纷繁复杂、有条不紊的 word 文档。本节通过构建这些基本元素,来剖析一篇 word 文档的构建过程。

在 word 文档中,都是通过各级标题来组织章节。对应到 HTML 中,使用标题元素 h1 ~ h6 来定义文档的各级标题,标题元素采用层次结构,h1 表示一级标题,h2 表示二级标题,以此类推。如:

<h1>CSS的选择器</h1>
<h2>基本选择器</h2>
<h3>元素选择器</h3>
<h3>类选择器</h3>
<h3>id选择器</h3>
<h3>群组选择器</h3>
<h2>关系选择器</h2>
<h3>后代选择器</h3>
<h3>子选择器</h3>
<h3>相邻同胞选择器</h3>
<h3>同胞选择器</h3>

默认情况下,浏览器会把标题渲染为加粗字体,h1 的字体最大,h6 的字体最小,表示内容的重要性逐级降低。并且,为了防止标题和内容过分拥挤,浏览器通常会在标题的上下,各留出一定的间隙。

浏览器的默认效果,不可能满足所有人的要求。所以,CSS 设计师通常会根据需要,来重置标题的样式,如外边距、内边距、字体样式等,以满足自己的要求。如:

h1,
h2,
h3 {
  margin: 0;
  padding: 0;
  font-weight: normal;
}

标题为块级元素,可以设置边距、边框、背景、字体、文本等相关样式。这些都非常简单,并且在前面已经有过详细介绍,这里就不再赘述。

众所周知,word 有一项非常人性化的功能,就是用户可以随意增删任何一级标题,而不必人工重新修改编号,这些都由 word 自动完成。而我们制作的网页版 word 能否具备此功能呢?接下来,带领大家一起探索一下。

可以想象,标题的编号,其实就是在标题文本的前面,插入一个可以自动计数的计数器。

在 CSS 中,使用伪元素选择器 E::before,可以在元素前面插入内容,而插入的内容由content 属性生成。如果把 content 属性的值设置为某个计数器,即可把计数器的值插入到元素的前面。格式如下:

E::before {
  content: counter(计数器名称);
}

借助这个功能,就可以实现标题的自动编号功能。其实,属性值 counter 只是对计数器的引用而已,计数器还要在其它待计数的选择器中定义。CSS 中,使用 counter-increment属性来定义计数器,其名称可以是任意合法的字符串。

h1 {
  counter-increment: counter_h1;
}
h1::before {
  content: counter(counter_h1);
}

上述代码,在选择器 h1 中定义了名称为 counter_h1 的计数器,并在 h1::before 选择器中引用了该计数器,即可把计数器的值插入到 h1 的前面。可以使用同样的方法,来定义 h2、h3 标题前插入的内容。运行结果如图 1-1 所示:

图 1-1 各级标题连续编号

从上图可以看出,所有的 h3 标题为统一编号(见红线标注),应该是每个 h2 下的 h3 各自独立编号。

如果要将 h2 下的 h3 重新编号,还需要在 h2 中,使用 counter-reset 属性,来重置指定的计数器。这里需要重置的是 h2 中的 counter_h3 计数器。

h2 {
  counter-increment: counter_h2;
  counter-reset: counter_h3;
}

经过上述修改后,运行结果如图 1‑2 所示:

图 1-2 重置自动编号

从上图可以看出,h2 下的 h3 确实独立编号了。但是,h1 和 h2 都是以 1、2、3 的形式进行编号,我们希望 h1 是“1.”、“2.”的形式,而 h2 是“1.1”、“2.1”的形式。

先看一级标题,其实就是希望在编号后添加一个 “.”。要在 content 的内容中添加固定的文本比较简单,只需把文本的内容添加到 content 属性值的指定位置即可。

h1::before {
  content: counter(counter_h1) '.';
}
h2::before {
  content: counter(counter_h1) '.' counter(counter_h2);
}

再看二级标题,二级标题要引用一级标题的序号。沿用以上的思路,直接把一级标题的计数器和 “.” 拿来,添加到 h1::before 的 content 属性值中即可。对三级标题,也采用同样的思路。

h3 {
  counter-increment: counter_h3;
}
h3::before {
  content: counter(counter_h1) '.' counter(counter_h2) '.' counter(counter_h3);
}

经过上述修改后,运行结果如图 1‑3 所示:

图 1-3 添加章节编号前缀

从上图可以看出,所有的编号都已经符合要求,但是标题文本和编号之间距离太小,过于拥挤。可以在插入内容的右侧,设置一定的内边距,使标题文本和编号之间保持一定距离。

h1::before,
h2::before,
h3::before {
  padding-right: 1em;
}

同理,为了有效区分各级标题,也可以通过左外边距为不同标题设置不同的缩进,让各级标题层次分明。

h1 {
  margin-left: 1em;
}
h2 {
  margin-left: 2em;
}
h3 {
  margin-left: 3em;
}

至此,标题的自动编号功能就完全实现了。运行结果如图 1‑4 所示:

图 1-4 章节自动编号

有了自动编号,就可以随意增删任何一级标题,再也不用担心编号发生混乱,也体现了 CSS 的强大。

在定义自动编号时,默认的编号类型是数字。当然,除数字外,也可以使用字母、罗马数字等,只需在 counter 中指定编号种类即可,编号种类可以是 list-style-type 属性能支持的任何值。如:

content: counter(counter_h1, lower-roman);

另外,counter-increment 属性默认是从 1 开始递增的。但是,可以提供第二个参数,让它从指定值开始递增。如:

counter-increment: counter_h1, 10;

其实,在 CSS1 中,就有了伪元素选择器,而 E:before 选择器是 CSS2 才引入的。到了 CSS3,伪元素选择器的语法发生了改变,E 和 before 之间的冒号,由一个变成了两个。但是,现代浏览器仍然支持老的语法,你仍然可以使用 E:before

纯 CSS 实现目录自动编号 (opens new window)