CSS 计数器

前言

前端页面上的计数排列一般比较常见的结构就两种:


图片左边的结构是一个导航目录,图片右边的结构一般可作为电商幻灯片的导航。在 HTML 层面我们实现这种效果一般使用 ulol。当然你也可以使用别的标签来实现。HTML 的 ulol 作为序列使用是非常好用的,唯一的遗憾就是序列号可用性比较差,虽然提供了 list-style-image。要想使用 ol 来实现前面带 1.1 的这种目录结构,还是比较难的。

这时候该是 css 计数器 counter 出场了。

API 介绍

css 计数器一共涉及,两个属性一个方法,如下:

  1. counter-reset
    功能是可以创建计数器即是给计数器命名的,也可以重置计数器。默认是 0。
.xxx{counter-reset: name;}/*创建一个为name的计数器,默认从0开始计数*/
.xxx{counter-reset: name 10;}/*创建一个为name的计数器,默认从10开始计数*/

多个计数器还可以这样写:

.xxx { counter-reset: name 1 name 2; }

另外,counter-reset 还可以设置为 none 和 inherit. 干掉重置以及继承重置。

  1. counter-increment
    递增/递减变量,计数器的增量/减量,1 个或多个关键字。后面如果跟随数字,表示每次计数的变化值。如果缺省,则使用默认增值 1。
.xxx{counter-increment: name;}/*name计数器每次增加1*/
.xxx{counter-increment: name 10;}/*name计数器每次增加10*/
.xxx{counter-increment: name -10;}/*name计数器每次减少10递减效果*/
  1. counter()/counters()
    将计数器的值添加到元素。计数的结果将通过counter()/counters()展示出来。
counter(name)/*把叫name的计数器展示出来,格式为1、2、3......*/

还有一种用法:

counter(name,style)

name 就是计数器的名字,style 是什么?默认递增递减是数字,style 就是用来自定义递增递减不是数字,例如可以是 a、b、c。 其支持的关键字值和 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
一个content属性值还可以有多个counter()方法。

一个简单的例子
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <style>
        html{
            background-color: #ffc9eb;
        }
        div{
            counter-reset: name;
        }
        p{
            counter-increment: name;
        }
        p::after{
            content: counter(name);
        }
    </style>
</head>
<body>
    <div>
        <p>section</p>
    </div>
</body>
</html>

看 section 后面是不是多了个 1?


代码解析:

  1. 通过 counter-reset 命名一个计数器叫 name,默认重 0 开始。
  2. 计数器在 div 标签上,它会照耀所有的子孙,计数器的递增在 p 标签上面默认增量为 1,标签展示的时候只要通过 p 就会增加 1。
  3. 计数器的展示,通过伪元素 (before 和 after) 里面的 content 配合 counter 或 counters。

下面讲一下最难得增量 counter-increment ,因其放的位置不同会引发不同的递增递减效果。

counter-increment 的位置

counter-increment 负责自增,只要其位置在 counter-reset 和 counter/counters 之间,展示时就会有增加的效果,计数器的解析规则和 HTML 的解析规则相同。所以 counter-increment 达到增加一次的效果,针对案例可以写的几种方式为:


自增一次

第一种:写在计数器定义和展示的中间

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>CSS计数器</title>
    <style>
        html{
            background-color: pink;
        }
        .reset{
            counter-reset: name 9;
        }
        .increment{
            counter-increment: name;
        }
        p::after{
            content: counter(name);
        }
    </style>
</head>
<body>
    <div class="reset">
        <div class="increment">自增
            <p>我后面是一个</p>
        </div>
    </div>
</body>
</html>

第二种:写在计数器定义的位置

<style>
    html{
        background-color: pink;
    }
    .reset{
        counter-reset: name 9;
        counter-increment: name;
    }
    p::after{
        content: counter(name);
    }
</style>

第三种:写在计数器展示的位置

<style>
    html{
        background-color: pink;
    }
    .reset{
        counter-reset: name 9;
    }
    p::after{
        counter-increment: name;
        content: counter(name);
    }
</style>

猜猜下面 h1 标签的伪类应该显示什么?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>CSS计数器</title>
    <style>
        html{
            background-color: pink;
        }
        .reset{
            counter-reset: name 10;
        }
        .increment{
            counter-increment: name 5;
        }
        h1::after,p::after{
            content: counter(name);
        }
    </style>
</head>
<body>
    <div class="reset">
        <div class="increment">自增
            <p>我后面是一个</p>
        </div>
        <h1>猜猜我的结果</h1>
    </div>
</body>
</html>
猜猜看

p 标签后面是 15,是没有问题的,h1 后面也是 15。不知道你猜对了没?根据 HTML 解析规则和计数器使用规则,到 p 标签的时候是 15 ,h1 显示的又是相同的计数器,所以 h1 和 p 计数相等。

针对上面代码,我们不动 HTML 里面的,只更改 CSS 里面的代码,改成如下代码所示,再次猜猜看:

<style>
    html{
        background-color: pink;
    }
    .reset{
        counter-reset: name 10;
        counter-increment: name 5;
    }
    .increment{
        counter-increment: name 5;
    }
    h1::after,p::after{
        counter-increment: name 5;
        content: counter(name);
    }
</style>

是不是很简单计数器的数值变化遵循 HTML 渲染顺序,遇到一个 increment 计数器就变化,什么时候 counter 输出就输出此时的计数值。

counters() 这个方法还是要说下的。虽然和 counter 相比就多了个字母 s, 但两者的功能还是有很大的不同。counters 可以理解为嵌套计数。

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

counters 的用法:

counters(name, string, style)

name 就是计数器的名字,string 表示子序号的连接字符串。例如 1.1string 就是'.', 1-1就是 '-'。style 与 counter() 的 style 参数使用一致。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>CSS计数器</title>
    <style>
        html{
            background-color: pink;
        }
        .reset{
            counter-reset: name;
        }
        .item{
            text-indent: 2em;
        }
        .d2{
            text-indent: 4em;
        }
        .d3{
            text-indent: 6em;
        }
        .item::before{
            counter-increment: name;
            content:counters(name,"-")  '. ';
        }
    </style>
</head>
<body>
    <div class="reset">
        <div class="content">目录</div>
        <div class="item">
            术语
            <div class="reset">
                <div class="item d2">docker client</div>
                <div class="item d2">docker host</div>
                <div class="item d2">docker daemon</div>
                <div class="item d2">container</div>
                <div class="item d2">registry</div>
            </div>
        </div>
        <div class="item">
            安装 docker
            <div class="reset">
                <div class="item d2">
                    守护进程配置
                </div>
            </div>
        </div>
        <div class="item">
            底层原理
            <div class="reset">
                <div class="item d2">
                    namespace
                    <div class="reset">
                        <div class="item d3">pid: 隔离进程</div>
                        <div class="item d3">net: 隔离网络</div>
                        <div class="item d3">ipc: 隔离 IPC</div>
                        <div class="item d3">mnt: 隔离文件系统挂载</div>
                        <div class="item d3">uts: 隔离hostname</div>
                        <div class="item d3">user: 隔离uid/gid</div>
                    </div>
                </div>
                <div class="item d2">control groups</div>
                <div class="item d2">union file system</div>
            </div>
        </div>
        <div class="item">
            镜像
            <div class="reset">
                <div class="item d2">镜像仓库与拉取</div>
                <div class="item d2">构建镜像与发布</div>
            </div>
        </div>
        <div class="item">
            Dockerfile
            <div class="reset">
                <div class="item d2">FROM</div>
                <div class="item d2">ADD</div>
                <div class="item d2">COPY</div>
                <div class="item d2">CMD</div>
                <div class="item d2">ENTRYPOINT</div>
            </div>          
        </div>
        <div class="item">
            容器
            <div class="reset">
                <div class="item d2">创建容器</div>
                <div class="item d2">容器管理</div>
            </div>              
        </div>
    </div>
</body>
</html>

代码测试结果:


写给前端工程师的 docker 简易入门目录

最后注意:

一个元素,如果设置了 counter-increment 属性, 这个元素还设置了 display:none 或在标签上直接设置 hidden 属性 (<span hidde></span>)计数在此元素上失效。

感兴趣的还可以研究下下面这个案例,没写 JS 代码但是是动态的:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>CSS计数器</title>
    <style>
        body {
            counter-reset: icecream;
        }
        input:checked {
            counter-increment: icecream;
        }
        .total::after {
            content: counter(icecream);
        }
    </style>
</head>
<body>
    <strong>下面中国十大冰淇淋你吃过几个?</strong>
    <ol>
        <li><input type="checkbox" id="icecream1"><label for="icecream1">哈根达斯</label></li>
        <li><input type="checkbox" id="icecream2"><label for="icecream2">和路雪wall's</label></li>
        <li><input type="checkbox" id="icecream3"><label for="icecream3">八喜冰淇淋</label></li>
        <li><input type="checkbox" id="icecream4"><label for="icecream4">DQ冰淇淋</label></li>
        <li><input type="checkbox" id="icecream5"><label for="icecream5">蒙牛冰淇淋</label></li>
        <li><input type="checkbox" id="icecream6"><label for="icecream6">雀巢冰淇淋</label></li>
        <li><input type="checkbox" id="icecream7"><label for="icecream7">伊利冰淇淋</label></li>    
        <li><input type="checkbox" id="icecream8"><label for="icecream8">乐可可冰淇淋</label></li>
        <li><input type="checkbox" id="icecream9"><label for="icecream9">新城市冰淇淋</label></li>
        <li><input type="checkbox" id="icecream10"><label for="icecream10">明治MEIJI</label></li>
    </ol>
    你总共选择了 <strong class="total"></strong> 款冰淇淋!
</body>
</html>


还可以使用 CSS 计数器实现数值计算小游戏

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,258评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,335评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,225评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,126评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,140评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,098评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,018评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,857评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,298评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,518评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,400评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,993评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,638评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,661评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容

  • CSS 里面的伪元素其实是非常好用的,但是经常容易被大家忽略,伪元素里面常用到的 content 属性,可能现在很...
    大前端世界阅读 466评论 0 4
  • CSS 计数器简介 蓝线关注 2018.04.07 12:54字数 1113阅读 10评论 0喜欢 0 CSS 计...
    小杰的简书阅读 318评论 0 3
  • CSS 计数器(counter)是由 CSS 维护的变量,其主要用途是,可以通过指定的规则来计算节点元素的使用次数...
    蓝线阅读 384评论 0 1
  • 先来看一下这几个属性 counter-reset 计数器重置 参数1.计数器名称2.计数器初始值默认值为0,必须为...
    漫卷0823阅读 254评论 0 2
  • 1. CSS伪类 CSS伪类分为两类:状态性和结构性; (1)状态性伪类根据当前元素状态进行选择。当元素处于某状态...
    西柚喃木阅读 1,036评论 0 1