一、CSS计数器三角关系

CSS计数器只能跟content属性在一起的时候才有作用,而content属性貌似专门用在before/after伪元素上的。于是,就有了,“计数器↔伪元素↔content属性”的铁三角关系。

二、CSS计数器成员

举例班级中成员依次报名

其中有这么几个关键点:
1. 班级命名。总不能六脉神剑一指,你,侬,汝来称呼吧~有个称呼,如生信4班,就知道谁的是谁了。
2. 报数规则。1,2,3,4递增报数,还是1,2,1,2报数,让班级的人知道。
3. 开始报数。不发口令,大眼瞪小眼,会乱了秩序。

巧的是,以上3个关键点正好对应CSS计数器的2个属性和1个方法,依次是:
1. counter-reset
2. counter-increment
3. counter()/counters()

1. counter-reset

顾名思意,就是“计数器-重置”的意思。其实就是“班级命名”,主要作用就是给计数器起个名字。如果可能,顺便告诉下从哪个数字开始计数。默认是0, 注意,默认是0而不是1. 可能有同学回疑惑,尼玛网上的各种例子默认显示的第1个数字不都是1吗?那是因为受了counter-increment普照的影响,后面会详细讲解。

OK, 这里,我们先看两个简单的counter-reset的例子:

.xxx { counter-reset: small-apple; } /* 计数器名称是'small-apple' */
.xxx { counter-reset: small-apple 2; } /* 计数器名称是'small-apple', 并且默认起始值是2 */

demo:

.contaner1 {
counter-reset: number;
} .contaner1:before {
content: counter(number);
} .contaner2 {
counter-reset: number 1;
} .contaner2:before {
content: counter(number);
}
<div class="row">
<div class="contaner1">定义一个名称开始编号</div>
</div>
<div class="row">
<div class="contaner2">定义一个名称开始编号,定义初始值为1</div>
</div>

  

counter-reset的计数重置可以是负数,例如-2。也可以写成小数,例如2.99,不过就是IE和FireFox都不识别,认为是不合法数值,直接无视,当作默认值0来处理;不过Chrome不嫌贫嫉富,任何小数都是向下取整,如2.99当成2处理,于是王小二还是那个王小二。

到此为止?非也非也!counter-reset还有一手,就是多个计数器同时命名。例如,王小二和王小三同时登台:

demo:
.contaner5 {
counter-reset: number 3 number1 4;
} .contaner5:before {
content: counter(number) '\A' counter(number1);
}

<div class="row">
<div class="contaner5">定义两个计数器,第一个从3开始,第二个从4开始</div>
</div>
 

直接空格分隔,譬如逗号什么的都不行。

另外,counter-reset还可以设置为noneinherit. 干掉重置以及继承重置。你懂的,就不展开了。

2. counter-increment

顾名思意,就是“计数器-递增”的意思。值为counter-reset的1个或多个关键字。后面可以跟随数字,表示每次计数的变化值。如果缺省,则使用默认变化值1(方便起见,下面的都使用默认值做说明)。

CSS的计数器的计数是有一套规则的,我将之形象地称为“普照规则”。具体来讲就是:普照源(counter-reset)唯一,每普照(counter-increment)1次,普照源增加1次计数值。

于是,我们可以解释上面提到的“默认值是0”的问题。通常CSS计数器应用的时候,我们都会使用counter-increment, 肯定要用这个,否则怎么递增呢!而且一般都是1次普照,正好+1,第一个计数的值就是1啦(0+1=1)!

下面,通过几个例子,给大家形象地展示下普照规则

Demo相关核心代码为:

.contaner3 {
counter-reset: number 1;
counter-increment: number;
} .contaner3:before {
content: counter(number);
}
<div class="row">
<div class="contaner3">定义一个名称开始编号,定义初始值为1,定义它的编码规则 每次自增1(只有父元素)</div>
</div>

这里counter-increment普照了p标签,counter-reset值增加,默认递增1,于是计数从设置的初始值2变成了3wangxiaoer就是这里的计数器,自然伪元素content值counter(wangxiaoer)就是3.

当然,也可以普照自身,也就是counter-increment直接设置在子元素上:

.contaner7 {
counter-reset: number 1;
} .contaner7:before {
counter-increment: number;
content: counter(number);
}
<div class="row">
<div class="contaner7">定义一个名称开始编号,定义初始值为1,定义它的编码规则 每次自增1(只有子元素)</div>
</div>
 

依然是1次普照,依旧全局的计数器+1,所以,显示的数值还是3().

趁热打铁。如果父元素和子元素都被counter-increment普照1遍,结果会如何呢?

很简单的,父元素1次普照,子元素1次普照,共两次普照,counter-reset设置的计数器值增加2次,计数起始值是1,于是现实的数字就是3啦!

.contaner4 {
counter-reset: number 1;
counter-increment: number;
} .contaner4:before {
content: counter(number);
counter-increment: number;
}
<div class="row">
<div class="contaner4">定义一个名称开始编号,定义初始值为1,定义它的编码规则 每次自增1(父元素和子元素都有)</div>
</div>  

总而言之,无论位置在何方,只要有counter-increment,对应的计数器的值就会变化,counter()只是输出而已!

理解了“普照规则”,则以我们通常的计数器递增效果也可以理解了。

考虑下面这两个问题:

  1. 爸爸受到普照,且重置默认值0,爸爸有2个孩子。孩子自身都没有普照。两个孩子的计数值是?
  2. 爸爸没有普照,重置默认值0,爸爸有2个孩子。孩子自身都接受普照。两个孩子的计数值是?

答案是:1,1和1,2!

哦?答案居然不一样,有什么差别呢?

很简单。什么爸爸,孩子你都不要关心。只要看被普照了几次。情况1就爸爸被普照,因此,计数器增加1次,此时两个孩子的counter自然都是1; 情况2,两个孩子被普照,普照2次,第1个孩子普照之时,计数器+1,也就是1;第2个孩子普照之时再+1,于是就是2. 于是,两个孩子的counter输出就是1,2.

.row4 .contaner6:before {
counter-increment: number;
content: counter(number);
}
.row4 {
counter-reset: number 1;
}
<div class="row4 row">
<div class="contaner6">自动标号-递增---初始值是1---每次自增1(默认是1)</div>
<div class="contaner6">自动标号-递增---初始值是1---每次自增1(默认是1)</div>
<div class="contaner6">自动标号-递增---初始值是1---每次自增1(默认是1)</div>
<div class="contaner6">自动标号-递增---初始值是1---每次自增1(默认是1)</div>
<div class="contaner6">自动标号-递增---初始值是1---每次自增1(默认是1)</div>
<div class="contaner6">自动标号-递增---初始值是1---每次自增1(默认是1)</div>
</div>

  

计数器的数值变化遵循HTML渲染顺序,遇到一个increment计数器就变化,什么时候counter输出就输出此时的计数值。看懂了下图,您自然就会全然明白“普照规则”了。

counter-increment其他设定
counter-reset可以一次命名两个计数器名称,counter-increment自然有与之呼应的设定,也是名称留空就可以了。

正如本节开始提到的,这变化的值不一定是1,我们可以灵活设置。例如:

counter-increment: counter 2

那就是偶数偶数的增加。例如下面这个变身:

还可以是负数,例如:

counter-increment: counter -1
.row2 {
counter-reset: number 0;
} .row2 .contaner6:before {
counter-increment: number -1;
content: counter(number);
}
<div class="row2 row ">
<div class="contaner6">自动标号--递减--初始值是0(默认是0)----每次自减1(默认是1)</div>
<div class="contaner6">自动标号--递减--初始值是0(默认是0)----每次自减1(默认是1)</div>
<div class="contaner6">自动标号--递减--初始值是0(默认是0)----每次自减1(默认是1)</div>
<div class="contaner6">自动标号--递减--初始值是0(默认是0)----每次自减1(默认是1)</div>
<div class="contaner6">自动标号--递减--初始值是0(默认是0)----每次自减1(默认是1)</div>
<div class="contaner6">自动标号--递减--初始值是0(默认是0)----每次自减1(默认是1)</div>
<div class="contaner6">自动标号--递减--初始值是0(默认是0)----每次自减1(默认是1)</div>
</div>

  

就有了递减排序效果啦!

值还可以是none或者inherit.

3. counter()/counters()

这是个方法,不是属性。类似CSS3中才calc()计算。这里作用很单纯显示计数。不过名称、用法有多个:

 目前为止,我们看到的是最简单的用法:

counter(name) /* name就是counter-reset的名称 */

 那下面这个语法是什么意思呢?

counter(name, style)

这里的style参数还有有些名堂的。其支持的关键字值就是list-style-type支持的那些值。作用是,我们递增递减可以不一定是数字,还可以是英文字母,或者罗马文等。

list-style-type:disc | circle | square | decimal | lower-roman | upper-roman | lower-alpha | upper-alpha | none | armenian | cjk-ideographic | georgian | lower-greek | hebrew | hiragana | hiragana-iroha | katakana | katakana-iroha | lower-latin | upper-latin

.row1 {
counter-reset: number 1;
}
.row1 .contaner6:before {
counter-increment: number;
content: counter(number,upper-roman);
}
<div class="row1 row">
<div class="contaner6">自动标号-递增---初始值是1---每次自增1(默认是1)</div>
<div class="contaner6">自动标号-递增---初始值是1---每次自增1(默认是1)</div>
<div class="contaner6">自动标号-递增---初始值是1---每次自增1(默认是1)</div>
<div class="contaner6">自动标号-递增---初始值是1---每次自增1(默认是1)</div>
<div class="contaner6">自动标号-递增---初始值是1---每次自增1(默认是1)</div>
<div class="contaner6">自动标号-递增---初始值是1---每次自增1(默认是1)</div>
</div>

  

 counter还支持级联。也就是一个content属性值可以有多个counter()方法。

上面CSS源代码使用'\A'使用inline水平元素换行,此技术若有兴趣,可参考之前的“使用CSS(Unicode字符)让inline水平元素换行”一文。

 下面介绍下counters()方法。看似值多了个字母s, 但表意大变身。counters几乎可以说是嵌套计数的代名词。

我们平时的序号,不可能就只是1,2,3,4,.., 还会有诸如 1.1,1.2,1.3,...等的子序号。得,前者就是counter()干的事情,后者就是counters()干的事情。

基本用法为:

counters(name, string); /* MDN上说,要想IE8兼容,这里逗号后面的空格要去掉,但是鄙人IE11的IE8模式看,无此问题 */

其中,string参数为字符串(需要引号包围的)(必须参数),表示子序号的连接字符串。例如1.1string就是'.'1-1就是'-'.

看上去很简单。但是,如果理解不是很深刻,日后在使用肯定会遇到麻烦——“咦?怎么没有子序列,明明语法正确的啊?”首先,记住这一句话,“普照源是唯一的”,所以,如果你在只在body标签上设置counter-reset,就算里面的子元素嵌套了祖宗十八代,还是不会有任何嵌套序号出现的!

所以,要想实现嵌套,必须让每一个列表容器拥有一个“普照源”,通过子辈对父辈的counter-reset重置、配合counters()方法才能实现计数嵌套效果。

.row3{ counter-reset:number 0;}
.row3 .contaner6:before{
counter-increment: number 1;
content:counters(number,"-") '.';
}
<div class="row3 row">
<div class="contaner6">自动标号----第一级
<div class="row3">
<div class="contaner6">
自动标号-----第二级
<div class="row3">
<div class="contaner6">
自动标号-----第三级
<div class="row3">
<div class="contaner6">自动标号-----第四级</div>
<div class="contaner6">自动标号-----第四级</div>
<div class="contaner6">自动标号-----第四级</div>
<div class="contaner6">自动标号-----第四级</div>
<div class="contaner6">自动标号-----第四级</div>
</div>
</div>
<div class="contaner6">自动标号</div>
<div class="contaner6">自动标号</div>
<div class="contaner6">自动标号</div>
<div class="contaner6">自动标号</div>
</div>
</div>
<div class="contaner6">自动标号</div>
<div class="contaner6">自动标号</div>
<div class="contaner6">自动标号</div>
<div class="contaner6">自动标号</div>
</div>
</div>
<div class="contaner6">自动标号</div>
<div class="contaner6">自动标号</div>
<div class="contaner6">自动标号</div>
<div class="contaner6">自动标号</div>
<div class="contaner6">自动标号</div>
</div>

  

也会遇到这样的麻烦——“咦,怎么子序列不按层级顺序来啊,命名语法正确啊?” 还是要记住这一句话:“一个容器里的普照源(reset)是唯一的”,所以,

如果你不小心把计数显示和技术reset元素以兄弟元素形式放在一起(虽然HTML内容布局呈现是没有异常的),就很可能会出现计数序号乱入的情况。

会看到标红的部分的序号显示异常了!

为何会出现这个问题,我们看下HTML(主要是注释):

<div class="reset">
<div class="counter">我是王小二</div>
<div class="reset"><-- 这里的reset与上面的counter是兄弟关系,而不是父子关系。虽然布局渲染上没有差异。但是,一个容器的reset的唯一的,一旦子元素出现reset,会改变整个容器的嵌套关系,于是,后面的“王小三”、“王小四”其实已经进入了2级嵌套,因此显示的是1-3和1-4 -->
...
</div>
<div class="counter">我是王小三</div>
<div class="counter">我是王小四</div>
<div class="reset">
<div class="counter">我是王小四的大儿子</div>
</div>
</div>

如果上面的注释没看明白,您可以跟前面没有问题的demo做下HTML结构对比,或许就会豁然开朗!

 counters()也是支持style自定义递增形式的。

counters(name, string, style)

counter()style参数使用一致,不赘述。

四、CSS计数器与display:none

一个元素,如果设置了counter-increment, 但是其display的属性值是none或者含有hidden属性(针对支持浏览器),则此计数值是不会增加的。而visibility:hidden以及其他声明不会有此现象。

五、CSS计数器实际应用

相比传统的ol,ul列表计数,CSS计数器的优势就在于灵活与强大,不足就是IE6/IE7不支持。

普照规则第一条,普照源唯一。所以,我们可以在头尾放两个差距甚远的列表,然后,这些列表自动显示序号。而ol/ul只能写死start实现,很不灵活,一旦列表有删减,就嗝屁了。

由于计数器是伪元素控制显示的。因此,我们几乎可以应用各种CSS样式,各种定位等。所以,基本上,只要有有序序号呈现的地方,就能使用CSS计数器。

例如,电商首页的图片slide广告上的1,2,3,4,...序号;

我们做分享时候使用的HTML5 web在线幻灯片就可以使用CSS计数器标注页数等;以及一开始给小伙伴们做的果汁工具的3个选择等。

参考文章

本文原创地址:http://www.zhangxinxu.com/wordpress/?p=4303

CSS counter计数器(content目录序号自动递增)详解的更多相关文章

  1. CSS计数器(序列数字字符自动递增)详解———张鑫旭

    by zhangxinxu from http://www.zhangxinxu.com本文地址:http://www.zhangxinxu.com/wordpress/?p=4303 一.挖坟不可耻 ...

  2. CSS中伪类及伪元素用法详解

    CSS中伪类及伪元素用法详解   伪类的分类及作用: 注:该表引自W3School教程 伪元素的分类及作用: 接下来让博主通过一些生动的实例(之前的作业或小作品)来说明几种常用伪类的用法和效果,其他的 ...

  3. content = "IE=edge,chrome=1" 详解

    content = "IE=edge,chrome=1" 详解 < meta http-equiv = "X-UA-Compatible" content ...

  4. 【二次元的CSS】—— 用 DIV + CSS3 画咸蛋超人(详解步骤)

    [二次元的CSS]—— 用 DIV + CSS3 画咸蛋超人(详解步骤) 2016-05-17 HTML5cn 仅仅使用div作为身体的布局,用css3的各种transform和圆角属性来绘制各部位的 ...

  5. web前端学习(三)css学习笔记部分(6)-- 选择器详解

    9.选择器详解 9.1  属性选择器 CSS3 属性选择器,在 CSS3 中,追加了三个属性选择器分别为:[att*=val].[att^=val]和[att$=val],使得属性选择器有了通配符的概 ...

  6. linux系统/var/log目录下的信息详解

    一./var目录 /var 所有服务的登录的文件或错误信息文件(LOG FILES)都在/var/log下,此外,一些数据库如MySQL则在/var/lib下,还有,用户未读的邮件的默认存放地点为/v ...

  7. Tomcat的目录结构和配置文件详解

    本文转载: https://www.zybuluo.com/1234567890/note/515235 参考帖子: Tomcat(一):基础配置详解 Tomcat服务器中配置多个域名,访问不同的we ...

  8. 实时通讯系列目录篇之SignalR详解

    一. 简单说几句 最早使用SignalR的时候大约是两年前了,记得当时是一个OA中消息的实时提醒,轮询的方式有点耗资源,WebSocket写起来又比较麻烦,最终选择了SignalR,当时是什么版本已经 ...

  9. Snort里如何将读取的包记录存到指定的目录下(图文详解)

    不多说,直接上干货! 比如,在/root/log目录下. [root@datatest ~]# snort -dve -l /root/log 需要注意: 1) /log目录需要你自己建立,并修改权限 ...

随机推荐

  1. argument to nsmutablearray method addobject cannot be nil 警告

    You cannot add nil to an NSMutableArray, and you will raise an exception if you try to. There's NSNu ...

  2. android 弹出菜单

    <!-- 定义基础布局LinearLayout --> <LinearLayout xmlns:android="http://schemas.android.com/ap ...

  3. Linux服务器同步网络时间

    Linux服务器运行久时,系统时间就会存在一定的误差,一般情况下可以使用date命令进行时间设置,但在做数据库集群分片等操作时对多台机器的时间差是有要求的,此时就需要使用ntpdate进行时间同步. ...

  4. wc递归统计代码行数

    find /path -name '*.cpp' |xargs wc -l

  5. ime-mode:disabled (用css实现关闭文本框输入法)

    css 之 ime-mode语法:ime-mode : auto | active | inactive | disabled取值:auto : 默认值.不影响ime的状态.与不指定 ime-mode ...

  6. javascript 总结(持续更新)

    1.jQuery对象转DOM对象. jQuery对象转DOM对象有两种方法,[index]和get(index). var $cr = $("#cr"); //jQuery对象 v ...

  7. 移动Web开发实践

    移动设备的高速发展给用户带来了非常大的便利.用户使用Android.iPhone和其他移动设备非常easy接入互联网. 移动设备对网页的性能要求比較高.以下就说说Mobile Web开发的一些心得. ...

  8. HDU 6096 String 排序 + 线段树 + 扫描线

    String Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others) Problem De ...

  9. 记一次OGG数据写入HBase的丢失数据原因分析

    一.现象二.原因排查2.1 SparkStreaming程序排查2.2 Kafka数据验证2.3 查看OGG源码2.3.1 生成Kafka消息类2.3.2 Kafka配置类2.3.3 Kafka 消息 ...

  10. MySQL的简单优化

    一.如何发现需要优化的SQL 主要使用MySQL的慢查日志对有效率问题的SQL进行监控 第一步:启动慢查日志的监控 打开开关,将未使用索引的查询记录到慢查日志中 设置查询时间,当查询时间大于这个值,就 ...