CSS @counter-style规则详细介绍

这篇文章发布于 2021年10月25日,星期一,01:19,归类于 CSS相关。 阅读 14804 次, 今日 5 次 8 条评论

 

counter-style封面图

一、有序项目符号发展历史

在 Web 中,有序项目符号(无序项目符号一般是原点、圆圈、方块等图形,非本文要点,不予介绍)的发展经历了下面这几个阶段。

1. 数字和西方语系支持

在 HTML 中,项目符号可以使用 type 属性指定。

例如:

<ol type="A">
    <li>第一行</li>
    <li>第2行</li>
    <li>第3行</li>
</ol>

完整支持的属性值包括这些:

<ol type="1">
<ol type="a">
<ol type="A">
<ol type="i">
<ol type="I">

对应的序号如下图所示:

type属性有序符号

也可以使用 CSS 属性 list-style-type 指定。

/* 亚美尼亚 */
list-style-type: armenian;
/* 格鲁吉亚 */
list-style-type: georgian;
/* 十进制 */
list-style-type: decimal;
/* 十进制带零 */
list-style-type: decimal-leading-zero;
/* 小写字母 */
list-style-type: lower-alpha;
/* 小写希腊字母 */
list-style-type: lower-greek;
/* 小写拉丁字母 */
list-style-type: lower-latin;
/* 小写罗马字母 */
list-style-type: lower-roman;
/* 大写字母 */
list-style-type: upper-alpha;
/* 大写希腊字母 */
list-style-type: upper-greek;
/* 大写拉丁字母 */
list-style-type: upper-latin;
/* 大写罗马字母 */
list-style-type: upper-roman;

对应的效果如下图所示(左或上为 IE 浏览器、右或下是 Chrome 浏览器):

390 409

后来随着互联网发展,Web 页面遍布全球,西方语系的那些序号就不够用了。

比方说世界上上网语言所多的就是中文,但是中文居然不配有自动递增序号,这个像话吗?

于是,有序项目符号的发展,进入下一个阶段,即其他常见语系的支持。

2. 其他语言系统的支持

这里的语言系统就很多啦,中文日文韩文,简体繁体,还有一些生僻的压根没听过的,例如:

阿拉伯-印度语(arabic-indic)、孟加拉语 – bengali、柬埔寨语 – cambodian、梵语 – devanagari、埃塞俄比亚语 – ethiopic、古吉拉特语 – gujarati、果鲁穆奇语 – gurmukhi、卡纳达语 – kannada、高棉语 – khmer、老挝语 – lao、马拉亚拉姆语 – malayalam、蒙古语 – mongolian、缅甸语 – myanmar、东印度-雅利安波斯语(oriya)、波斯语 – persian、泰卢固语 – telugu、泰国语 – thai、藏语 – tibetan、乌尔都语 – urdu等。

比方说果鲁穆奇语(gurmukhi)的序号就是下面这样的(实时渲染效果):

  1. 第一行
  2. 第2行
  3. 第3行

截图效果这样:

果鲁穆奇语序号效果

想要查看其他语言的有序列表效果,可以狠狠地点击这里:其他语言系统下list-style项目符号demo

其中,中日韩三国语言占据的项目符号类型高达15个之多,包括:中日韩十进位(cjk-decimal)、中日韩地支(cjk-earthly-branch)、中日韩天干(cjk-heavenly-stem)、中日韩表意文字(cjk-ideographic)、日文正式(japanese-formal)、日文非正式(japanese-informal)、韩国韩语正式(korean-hangul-formal)、韩国汉字正式(korean-hanja-formal)、韩国汉字非正式(korean-hanja-informal)、简体中文正式(simp-chinese-formal)、简体中文非正式(simp-chinese-informal)、繁体中文正式(trad-chinese-formal)、繁体中文非正式(trad-chinese-informal)、韩语(hangul)、韩语辅音(hangul-consonant)。

例如“地支”可以实现子丑寅卯序号效果:

地支序号示意

然而,虽然扩展了很多有序列表关键字,但是全球那么多国家,都要枚举过来吗?

国家里面还有部落,部落有自己的语言,怎么样,要不要支持?

不支持岂不是歧视那些小国,歧视这些部落与邦郡?

就算所有国家都支持了,还有古代语言呢?

比方说中国古代的天地玄黄,支不支持?

如果不支持,古人岂不是会有意见,你们这是歧视我们古人!

好好好,既然,语言太多,处理不过来,那我就使用大招,直接制定一套规范,你们去自己DIY,你们想怎么玩,就怎么玩,老子不管了。

这个 DIY 就是本文要介绍的 @counter-style 规则,可以让任意的字符作为有序列表的项目符号呈现。

3. 世界语言太多,自己自己玩吧

@counter-style 规则使用示意:

@counter-style circled-alpha {
  system: fixed;
  symbols: Ⓐ Ⓑ Ⓒ Ⓓ Ⓔ Ⓕ Ⓖ Ⓗ Ⓘ Ⓙ Ⓚ Ⓛ Ⓜ Ⓝ Ⓞ Ⓟ Ⓠ Ⓡ Ⓢ Ⓣ Ⓤ Ⓥ Ⓦ Ⓧ Ⓨ Ⓩ;
  suffix: " ";
}

.items {
  list-style: circled-alpha;
}
<ol class="items">
    <li>元宇宙</li>
    <li>双十一</li>
    <li>CSS新世界</li>
</ol>

会产生如截图所示的列表:

自定义规则示意

喔噢,出现了,出现了,完全自定义的序号,这么一看,是不是还挺屌的。下面,就来好好了解下 @counter-style 规则的语法。

二、@counter-style规则语法

@counter-style 规则的基本结构如下:

@counter-style 任意自定义名称 {
    /* 具体的规则细节 */    
}

命名这块,虽然也支持驼峰命名,但是,通常约定俗成,按照行业习惯,都是使用短横线连接的,例如推荐使用:

@counter-style custom-style {}

而不是:

@counter-style customStyle {}

下面重点讲下具体的规则属性。

具体的规则属性

对于有序项目符号,我们需要哪些组合呢?

首先,肯定要指定都需要哪些符号,那,还有呢?

是不是可以指定下范围,指定下前缀和后缀,对不对?还可以指定需不需要补零之类的,还有范围不足的时候的兜底处理。

@counter-style 规则属性就是围绕上面的场景展开的,具体包括:

@counter-style counter-style-name {
    system: 计数系统
    symbols: 计数符号
    additive-symbols: 附加符号
    negative: 负数符号
    prefix: 前缀
    suffix: 后缀
    range: 范围
    pad: 补全
    speak-as: 如何阅读
    fallback: 备份计数规则
}

其中,speak-as大家可以忽略,这个属于无障碍访问相关的应用,大家目前无需了解。

至于其他几个属性还都挺有内容的,因此,单独拿出来讲下。

三、说说 system 属性

system 属性表示计数系统,也就是计数用的算法。支持下面这些值和用法:

/* 关键字值 */
system: cyclic;
system: numeric;
system: alphabetic;
system: symbolic;
system: additive;
system: fixed;

/* 组合使用值 */
system: fixed 3;
system: extends decimal;

下面直接通过案例带大家了解下各个关键字的作用。

1. cyclic

cyclic 表示循环使用开发者提供的一套字符,即如果计数到了末尾,会从头继续开始。

cyclic比较适合用在无序列表上,只需要指定一个字符,就可以无限循环使用,例如:

@counter-style smile {
    system: cyclic;
    symbols: ☺;
    suffix: " ";
}
ul {
   list-style-type: smile;
}

就会有如下图所示的效果,项目符号是个笑脸:

笑脸作为项目符号

如果指定的是多个符号,则会出现这几个字符不断循环的过程,例如:

@counter-style even-odd {
    system: cyclic;
    symbols: 奇 偶;
    suffix: " ";
}
ul {
    list-style-type: even-odd;
}

此时项目符号就是奇偶不断循环,看起来颇有点怪异。

奇偶项目符号示意

2. alphabetic

alphabetic 表示按字母编号系统将指定符号解释为数字。做多支持 a – z 共26个英文字母,如果顺序超过 z(或者指定字符数量),则会按照 “aa”, “ab”, “ac”… 继续解释项目符号。

例如:

@counter-style alphabetic {
    system: alphabetic;
    symbols: ⓐ ⓑ ⓒ;
    suffix: " ";
}
ul {
    list-style-type: alphabetic;
}

此时会有如下图所示的效果:

alphabetic 值效果示意

另外,如果 symbols 字符是不能直接用数字,或者是乱七八糟的符号表示的,否则自定义符号是无效的,一定要加引号才行,例如:

/* 无效 */
symbols: 1 2 3

* 有效 */
symbols: "1" "2" "3"

如果是中文或者中文全角标点,则不需要加引号。

3. numeric

numeric 表示使用数值系统符号计数算法,此算法和上面的 alphabetic 非常类似,区别在于,alphabetic 是从 1 开始的,后面是 2。而 numeric 是从 0 开始的,后面才是 1, 再然后是 2.

因此,numeric 值使用的时候需要保证至少 2 个字符被指定。

效果示意:

@counter-style numeric {
    system: numeric;
    symbols: ⓐ ⓑ ⓒ;
    suffix: " ";
}
ul {
    list-style-type: numeric;
}

此时会有如下图所示的效果:

numeric 值效果示意

可以看到第一个字符是 b,而不是 a,就是因为 a 对应的是 数字序号 0,而计数效果是从 1 开始的。

4. fixed

fixed 表示显示的序号字符是固定的,如果超出,不会循环,而是使用背后对应的数字代替呈现。

例如:

@counter-style fixed {
    system: fixed;
    symbols: ❶ ❷ ❸;
}
ul {
    list-style: fixed;
}

测试,前3个数字会使用实心数字代替,而后面的第4项和第5项由于没有指定项目字符,因此,还是使用默认的数字序号代替,如下截图所示:

实色文字序号示意

fixed 值还支持组合用法,例如:

system: fixed 3;

表示从第3项开始,使用指定的字符替换,于是,会有如下截图对应的渲染表现:

组合值效果截图

5. symbolic

symbolic 表示通过平铺字符的方式进行项目符号显示。

例如:

@counter-style symbolic {
    system: symbolic;
    symbols: ㊎ ㊍ ㊌;
}
ul {
    list-style: symbolic;
}

效果会是这样的,金木水字符不断平铺重复。

symbolic 字符平铺重复

6. additive

additive 表示“符号-值”编号系统,主要用在罗马数字上,因为罗马数字不是重复使用不同位置的数字以获得不同的值,而是为较大的值定义额外的数字。在这样一个系统中,数字的值可以通过在数字中加上数字来求出来。

必须使用至少一个加法元组指定名为加法符号的附加描述符,否则计数器样式规则将无效。

additive元组类似于复合计数器符号,它由两部分组成:正常计数器符号和非负整数权重。加法元组必须按其权重的降序指定,否则系统无效。

使用示意:

@counter-style my-upper-roman {
    system: additive;
    range: 1 3999;
    additive-symbols: 1000 M, 900 CM, 500 D, 400 CD, 100 C, 90 XC, 50 L, 40 XL, 10 X, 9 IX, 5 V, 4 IV, 1 I;
}
.additive {
    list-style: my-upper-roman;
}

接可以模拟原生的 list-style:upper-roman 效果:

大写罗马序号

additive 值特别适合超过一定序号,就突然改变字符显示的场景。

7. extends

extends 表示扩展自其他已有的计数规则,这个计数规则可以是浏览器内置的,例如字符递增,数字递增,中文递增等,也可以扩展自 @counter-style 规则自定义的计数规则。

下面这个案例示意的是扩展浏览器内置的甲乙丙丁中文天干规则弄的个10月新番排序:

@counter-style october-comic {
    system: extends cjk-heavenly-stem;
    prefix: "[10月新番]";
    suffix: "、";
}
.extends {
    list-style: october-comic;
    padding-left: 8em;
}

主要是自定义了前缀和后缀,效果就是下面这样:

通过扩展自定义新的计数规则

以上所有案例demo

以上所有截图和 system 值效果均可以体验,建议 Chrome 91+ 浏览器打开,您可以狠狠地点击这里:@counter-style规则下system各值demo

四、关于 symbols 和 additive-symbols

1. symbols

symbols 属性表示项目符合字符内容,语法上,这些字符可以有引号,也可以没有引号(数字必须加引号)。

例如下面的语法都是合法的:

symbols: A B C D E;
symbols: "\24B6" "\24B7" "\24B8" D E;
symbols: "0" "1" "2" "4" "5" "6" "7" "8" "9";

这里,顺便展示下天干地支对应的转义编码吧:

/* 子 丑 寅 卯 辰 巳 午 未 申 酉 戌 亥 */
symbols: "\5B50" "\4E11" "\5BC5" "\536F" "\8FB0" "\5DF3" "\5348" "\672A" "\7533" "\9149" "\620C" "\4EA5";
/* 甲 乙 丙 丁 戊 己 庚 辛 壬 癸 */
symbols: "\7532" "\4E59" "\4E19" "\4E01" "\620A" "\5DF1" "\5E9A" "\8F9B" "\58EC" "\7678";

symbols 属性还支持使用图像作为符号,例如:

symbols: url('first.svg') url('second.svg') url('third.svg');

不过目前没有任何浏览器支持这一特性,我估计在很长一段时间内,浏览器也不会支持的。

另外,如果 system 属性的值是 additive,则symbols 属性无效,需要使用 additive-symbols 属性表示描述符。

2. additive-symbols

additive-symbols 表示当计数值到了某一指定值的时候,项目符号使用对应字符代替,例如:

additive-symbols: 3 "0", 2 "1";

表示列表计数需要到2的时候项目符号显示字符串 1,计数是 3 的时候显示项目符号是 0。

additive-symbols 属性必须 system 属性的值是 additive 的时候使用。

同时,注意,计数序号一定要是倒序呈现的。例如,下面这样书写就是无效的:

/* 无效 */
additive-symbols:  2 "1", 3 "0";

举个例子,希望前3名使用状元、榜眼、探花称呼代替,而不是1,2,3,4,5,则可以试试下面的代码(也可以使用 fixed 计数算法):

@counter-style nba-draft {
    system: additive;
    additive-symbols: 探花 3, 榜眼 2, 状元 1;
    range: 1 3;
}
.draft {
    list-style-type: nba-draft;
}
<ul class="draft">
    <li>凯德·坎宁安(活塞)</li>
    <li>杰伦·格林(火箭)</li>
    <li>埃文·莫布里(骑士)</li>
    <li>斯科蒂·巴恩斯(猛龙)</li>
    <li>杰伦·萨格斯(魔术)</li>
</ul>

就可以实现预期的效果:

指定前三名的名称

眼见为实,您可以狠狠地点击这里:@counter-style规则下additive-symbols属性demo

五、前缀 prefix 和后缀 suffix

这里的知识没什么好说的,看示例:

prefix: "»";
prefix: "页码 ";
prefix: url(bullet.png);

prefix: "、";
prefix: ":";

支持任意数量的字符,支持图像类型。

六、pad 字符补全

这个直接看个例子就知道什么意思了(案例源自 MDN 文档):

@counter-style pad-example {
  system: numeric;
  symbols: "0" "1" "2" "3" "4" "5";
  pad: 2 "0";
}

.list {
  list-style: pad-example;
}

结果如下图,数字前面都补充了一个 0,这样,保证字符个数是 2 位。

补零效果示意

语法

pad 属性语法示意:

pad: 3 "0";

前面一个整数指需要补全的字符个数,后面的字符表示需要补全的字符。

七、指定应用计数规则的范围

这个是使用 range 属性实现的。

例如,希望某个数值范围,或者某几段数值范围全部使用自定义的计数规则,其他地方依然使用默认的计数规则(就是1,2,3,4,5这样递增),range 属性就非常合适。

additive-symbols 属性那里的demo案例已经展示了 range 属性的使用,这里不再重复添加演示说。

不过语法这块,有个东西要讲下,那就是 range 属性支持一个名为 infinite 的关键字,其实表示的是计数的边界。

一些使用示意:

range: infinite 10;

表示应该计数的范围从一开始到数字10.

range: infinite 6, 10 infinite;

表示7,8,9这3个计数不匹配自定义的计数规则。

例如下面这个代码:

@counter-style range-infinite-example {
    system: extends cjk-decimal;
    range: infinite 6, 10 infinite;
}
ul {
    list-style: range-infinite-example;
}

可以看到第7-9项前面是数字,而非中文。

range属性infinite关键字值的表现

八、兜底计数的fallback

fallback 可以和 systemsymbols 属性同时使用,表示如果计数范围溢出,该时候什么规则,默认情况下是1,2,3,4,5数值计数,我们可以通过 fallback 属性进行改变。

还是 additive-symbols 属性这里状元选秀的案例,如果我们在计数规则中增加这么一行 fallback 声明:

@counter-style nba-draft {
    system: additive;
    additive-symbols: 探花 3, 榜眼 2, 状元 1;
    range: 1 3;
    fallback: cjk-decimal;
}
.draft {
    list-style-type: nba-draft;
}

第4项和第5项前面就是数值了。

截图真实Windows Chrome下的渲染表现:

fallback 改变默认计数规则

效果可以访问此demo查看。

至此,所有 @counter-style 规则下的 CSS 属性都介绍完了,学完之后,会发现相关的规则设计,考虑的细节还是很多的,可谓是面面俱到,基本上,所有的有序计数场景都可以实现了。

兼容性

目前 Chrome 和 Firefox 都是支持的,Safari 浏览器拖了后腿。

@counter-style规则兼容性

补充

文章出现了不少特殊的有序字符,是从我珍藏多年的“乱七八糟字符合集”中复制过来的。

九、又要被领导吐槽了

一看时间 00:59,加上配图一系列工作,洗洗漱漱,1:30之前休息悬了。

本文已经很长了,结语就免了,欢迎分享,让更多人看到,不枉我吐血创作了。

(本篇完)

分享到:


发表评论(目前8 条评论)

  1. silence0_o说道:

    这个有意思啊

  2. suwanbin说道:

    感谢分享,这里指出个小问题:

    三、说说 system 属性 —— 5. symbolic
    里的代码贴错了哦

    @counter-style symbolic {
    system: symbolic;
    symbols: ㊎ ㊍ ㊌;
    }

  3. 王大锤说道:

    各位大佬,有啥技巧能让canvas实现像PS那样根据操作轴实现变形,如果把一个美女图片的水桶腰变成S形,会不会很有成就感?

  4. Canace说道:

    感觉发现了新大陆,nice

  5. 风华和血月说道:

    学到了!感谢感谢

  6. mfk说道:

    很多网站排行榜前3名会用特殊的艺术字体或不同图片。比如“金牌图片”、“银牌图片”、“铜牌图片”、4、5、6。平时只能用伪元素+nth-child实现。

    要是浏览器支持使用@counter-style图像作为符号就好了。