带你了解css计数器——counters
第一次了解到这个css是因为代码高亮-prismj中行号显示的实现。
当时很好奇前面的行号是如何实现的,一探究竟原来非常简单。
话不多说,先看代码。
一段css代码经过替换后的HTML:
<pre class="line-numbers language-css" data-src="plugins/line-numbers/prism-line-numbers.css"><code class=" language-css"><span class="token selector">pre.line-numbers</span> <span class="token punctuation">{</span>
<span class="token property">position</span><span class="token punctuation">:</span> relative<span class="token punctuation">;</span>
<span class="token property">padding-left</span><span class="token punctuation">:</span> 3.8em<span class="token punctuation">;</span>
<span class="token property">counter-reset</span><span class="token punctuation">:</span> linenumber<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span></code></pre>
生成的html无非就是把不同的关键字用不同的span
括起来,加上不同的样式,从而显示出不同的颜色,达到代码高亮的效果。我们重点关注其行号是如何实现的,相关css代码如下:
pre.line-numbers {
position: relative;
padding-left: 3.8em;
counter-reset: linenumber;
}
.line-numbers .line-numbers-rows {
font-size: 100%;
position: absolute;
top: 0;
left: -3.8em;
width: 3em;
user-select: none;
letter-spacing: -1px;
pointer-events: none;
border-right: 1px solid #999;
}
.line-numbers-rows>span {
display: block;
counter-increment: linenumber;
}
.line-numbers-rows>span:before {
display: block;
padding-right: .8em;
content: counter(linenumber);
text-align: right;
color: #999;
}
就能显示为如上所示的结构,css代码看起来多,实则不然,核心部分就三句:
遇到
line-numbers
时counter-reset: linenumber;
作用是重置名称为linenumber的计数器。遇到
.line-numbers-rows>span
时counter-increment: linenumber;
作用是此时名称为linenumber的计数器进行递增。在
line-numbers-rows>span
中创建一个伪元素,设置其content
为counter(linenumber)
,也就是在这个伪元素中显示这个计数器
See the Pen line-numbers by Douglas Chen (@cdswyda) on CodePen.
既然不知道,就还是来学习一下,一查才知道,这东西已经出现很多年了,不是什么新鲜玩意。 还是自己无知呀,学无止境。
css-counter的几个关键属性正好就是上面实现行号所用到的三部曲。
counter-reset
:必需值,必须用于选择器,主要用来标识该作用域,其值可以自定义。值语法为counter-reset: identifier [integer ]
,其中的identifier
即为计数器的名称,第二值integer
为计数器的初始值,默认为0,可接受任意整数值,默认为0,可省略。另外还可以一次定义多个如counter-reset: counter1 -10 counter1 10
。counter-increment
: 作用是遇到这个选择器匹配的元素时,计数器进行递增。语法格式为counter-increment:identifier [integer]
,identifier 为计时器名称,integer为一个整数值,表示每次递增的值(负数则为递减),默认为1,可省略。counter()/counters()
: 这个实际是个方法,可理解为获取计数器的值。通常将其作为伪元素的content
属性,从而将值显示出来。语法格式counter(name, style) / counters(name, string)
,counter 中的 style 是ul和ol中li元素所支持的list-style-type
的值,也就是你可以将1
显示为罗马数字i
;counters 则是表示可以使用指定的字符串将 计数器连接起来。
我们实现一个最简单的例子吧,给ul列表加上序号。
<ul>
<li class="item">列表条目1</li>
<li class="item">列表条目2</li>
<li class="item">列表条目3</li>
<li class="item">列表条目4</li>
<li class="item">列表条目5</li>
</ul>
<style>
ul {
/* 计数器 */
counter-reset: itemcounter;
list-style: none;
}
.item {
/* 每个item递增 */
counter-increment: itemcounter ;
}
.item:before {
/* 显示计数器 还可以拼接个顿号 */
content: counter(itemcounter) '、';
}
.item:after {
/* 试试转化为小写罗马数字 再显示到后面*/
content: '\'s index is ' counter(itemcounter,lower-roman);
}
</style>
效果如图:
挺简单嘛,论文或者各种文档中需要将标题标为1-1、1-1-1的形式是不是也可以用这个做呢,我们一起来试试。
<ul class="list-1">
<li class="level-1">
<span>一级标题1</span>
<ul class="list-2">
<li class="level-2">
<span>二级标题1</span>
</li>
<li class="level-2">
<span>二级标题2</span>
</li>
</ul>
</li>
<li class="level-1">
<span>一级标题2</span>
</li>
<li class="level-1">
<span>一级标题3</span>
<ul class="list-2">
<li class="level-2">
<span>二级标题1</span>
</li>
<li class="level-2">
<span>二级标题2</span>
</li>
</ul>
</li>
</ul>
<style>
.list-1 {
counter-reset: counter1;
list-style: none;
}
.list-2 {
counter-reset: counter2;
list-style: none;
}
.level-1 {
counter-increment: counter1;
}
.level-2 {
counter-increment: counter2;
}
.level-1:before {
content: counter(counter1) '、';
}
.level-2::before {
content: counter(counter1) '-' counter(counter2) '、';
}
</style>
效果果如图:
能实现,但是略显麻烦对不对。对于这种需要嵌套的使用 counters
就会变得方便很多。
<div class="reset">
<div class="item">一级标题1
<div class="reset">
<div class="item">二级标题1</div>
<div class="item">二级标题2
<div class="reset">
<div class="item">三级标题1</div>
<div class="item">三级标题2</div>
<div class="item">三级标题3</div>
</div>
</div>
<div class="item">二级标题3</div>
</div>
</div>
<div class="item">一级标题2</div>
<div class="item">一级标题3
<div class="reset">
<div class="item">二级标题1</div>
</div>
</div>
</div>
<style>
.reset {
line-height: 1.6;
padding-left: 20px;
counter-reset: itemcounter;
color: #666;
}
.item:before {
content: counters(itemcounter, "-") "、";
counter-increment: itemcounter;
}
</style>
效果:
一样的效果代码是不是简单了不少呢?