CSS实现有序列表编号方法知多少

1,039 阅读5分钟

这篇文章来自我们的特约作者——孟智强 同学,他之前的用CSS画一个冰墩墩的文章就广受称赞,来看看这里他分享的用CSS实现有序列表标号的知识

前言

内网某平台在页面首次打开时会弹一个框,其中包含一个带有编号的列表结构,好奇扒了下代码,发现列表的编号是放在 ul > li 标签下的 span 标签中的,这些数字编号应该是通过该平台的框架模板生成的,然后再利用 CSS 进行装饰,使其呈现带圈序号的样子。(见下图)

11_97615f304123444555ad65b44d432b7c_716x489.png@900-0-90-f.png

看到这里我可就不困了,一心想着能否通过 CSS 直接生成类似于上述编号的效果,从而省略掉 span 标签呢?

ol 标签

在前端开发中,提到编号必然会想到 ol 这个熟知的 HTML 标签,该标签表示一个带有编号的列表,缺省情况下自带阿拉伯数字编号(在编写业务 CSS 代码时,通常会重置该特性)。

例如下面的 HTML 代码:

<ol>
  <li>沉淀内心:每天抽出一定的时间来冥想、冥思、反省自己,让内心变得更加平静和深沉。</li>
  <li>培养兴趣:多尝试新事物,学习新技能,参与各种有意义的活动,让自己的兴趣爱好得到满足和提升。</li>
  <li>学会感恩:感激生命中的每一个美好瞬间和每个给予我们温暖、帮助和支持的人。</li>
  <li>保持谦虚:要时刻保持自我反省和谦虚的态度,学会接受批评,不断反省自己的不足之处,并努力改正。</li>
  <li>多一份善意:尽可能多地给予别人帮助和关爱,让身边的人感到温暖和幸福。</li>
</ol>

默认情况下会渲染为带有 1、2、3 这类序号的列表:

12_47a045bf05e6594b6fbd0e65f344df1b_823x168.png@900-0-90-f.png

不过很明显,这并不是我们想要的带圈数字的效果。我们接着往下看。

list-style-type

olul 标签的列表符号类型可通过 list-style-type 这个 CSS 属性来控制,该属性支持的值非常多,属性值渲染效果截图示意:

13_53460da889d472395ab2e687d2bb5df6_1271x920.png@900-0-90-f.png

然而,这其中并没有我们所需的带圈数字这种类型的效果,但我们同时也发现了一个有意思的点,那就是 list-style-type 的属性值支持自定义字符串(上图中最后一个示例)。换言之,若我们依次将 ①②③ 这类字符赋值给列表项的 list-style-type 属性,不就可以生成带圈数字的编号效果了吗?眼见为实:

<ol class="list">
  <li>沉淀内心:每天抽出一定的时间来冥想、冥思、反省自己,让内心变得更加平静和深沉。</li>
  <li>培养兴趣:多尝试新事物,学习新技能,参与各种有意义的活动,让自己的兴趣爱好得到满足和提升。</li>
  <li>学会感恩:感激生命中的每一个美好瞬间和每个给予我们温暖、帮助和支持的人。</li>
  <li>保持谦虚:要时刻保持自我反省和谦虚的态度,学会接受批评,不断反省自己的不足之处,并努力改正。</li>
  <li>多一份善意:尽可能多地给予别人帮助和关爱,让身边的人感到温暖和幸福。</li>
</ol>
.list > li:nth-child(1) {list-style-type: '① ';}
.list > li:nth-child(2) {list-style-type: '② ';}
.list > li:nth-child(3) {list-style-type: '③ ';}
.list > li:nth-child(4) {list-style-type: '④ ';}
.list > li:nth-child(5) {list-style-type: '⑤ ';}

效果如下:

14_ba8a6b5cacff35ba100276f32fdecde4_824x169.png@900-0-90-f.png

这个效果已经非常接近预期目标了,美中不足的是实现的 CSS 代码太过无脑,一点都不优雅!

@couter-style

在 CSS3 新规范中,list-style-type 还支持使用 @counter-style 规则自定义的符号列表。@counter-style 规则非常强大,允许开发者自定义他们自己的列表符号样式,可以实现几乎任何项目符号的效果。文档传送门

回到我们的需求,换成 @counter-style 实现的话只需寥寥几行,非常地优雅:

@counter-style circled-num {
  system: fixed;
  symbols: ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩;  /* 注意要用空格隔开,无需引号 */
  suffix: ' ';
}
.list {list-style: circled-num;}

效果如下:

5_95a3c7b71641fe7d86f18f47e02daf2c_830x170.png@900-0-90-f.png

再来个 emoji 字符的例子:

@counter-style emoji-clock {
  system: fixed;
  symbols: 🕐 🕑 🕒 🕓 🕔 🕕 🕖 🕗 🕘 🕙;
  suffix: ' ';
}
.list {list-style: emoji-clock;}

6_363eb371d5bf1ec3d3b047cf6e913f91_829x172.png@900-0-90-f.png

注意:Safari 浏览器目前还不支持 @couter-style

伪元素 + CSS计数器

像列表符号这种装饰性质的任务,利用伪元素来呈现也是个不错的方法,至于实现数字编号可以利用 CSS 计数器来生成。

先说下伪元素,CSS 伪元素规范第4版新出了一个 ::marker ,它作用在任何类型为 list-item 的元素上,例如在常见的 <li> 标签中就能一瞥它的身影:

7_67b26b73676b3e2c3d8262d5cf12b35b_1005x315.png@900-0-90-f.png

利用 ::marker 伪元素可以改变列表符号的颜色、字号、字体、甚至内容,但仅限于此,它并不支持诸如 widthmarginborder 等盒模型属性,所以可定制性方面大打折扣,最终还得是 ::before::after 出场。

再来说下 CSS 计数器,它是由 CSS 内部维护的变量,这些变量可根据定义的规则来递增或递减,利用 CSS 计数器可以自动为网页中的标题编号,或更改有序列表的编号。文档传送门

通过将伪元素和 CSS 计数器相结合,我们可以非常灵活且优雅地实现预期的目标。CSS 代码如下:

.list {
  list-style: none;  /* 移除缺省的列表编号 */
  counter-reset: order;  /* 初始化一个名为 order 的计数器 */
}
​
.list > li::before {
  content: counter(order);  /* 显示计数器当前的值 */
  counter-increment: order;  /* 递增计数器(缺省增量为1) */
  
  /* 下面是装饰类代码(略) */  
  border: 1px solid #575D6C;
  border-radius: 50%;
  ...
}

最终效果如下:

8_f898476bfccc7ed29d43fc3518a5f339_854x170.png@900-0-90-f.png

总结

  • list-style-type CSS 属性提供了大量常见的列表符号,可满足普通列表编号的需求。
  • list-style-type 支持自定义字符串,无序列表自定义符号的场景会用得上。
  • 使用 ::marker 伪元素可以对列表符号进行简单的定制。
  • @couter-style 提供更高级的编号类型定制。
  • 对于高度定制化的列表编号场景,可使用 ::before/::after 伪元素结合 CSS 计数器来实现。

参考资料