让你的有序无序列表更高级:CSS中@counter-style详解

一、使用场景

1.可恶的UI

当在项目中需要使用<ol></ol>或者<ul></ul>时,往往我们写出来的是最基本的朴实无华的样子 例如:

less 复制代码
//无序列表
<ul>
    <li>今天是个好日子</li>
    <li>风和日丽</li>
    <li>为什么我要加班</li>
    <li>我想回家睡觉</li>
    <li>写完这篇文章就回家</li>
</ul>
//有序列表
<ol>
    <li>今天是个好日子</li>
    <li>风和日丽</li>
    <li>为什么我要加班</li>
    <li>我想回家睡觉</li>
    <li>写完这篇文章就回家</li>
</ol>

出来的效果就是

这个时候万恶的UI就来提需求了 说这样不好看 不够美观 没艺术细胞...

一般解决方案是 无序列表的话 就和UI要个图替换ul自带的小黑点 有序列表呢就换一种序号,比如说换成罗马字母、英文等等。但如果UI不满足呢....比如UI想要第1-3条数据是一种符号☺ ,第5-8条数据是另一种符号 ❤️,或者要修改其颜色 大小等等..毕竟UI的脑洞非我们常人能及..

2.高级感!!逼格!!!

不管是无序列表还是有序列表,大多数人实现的效果都很单一,我们如何能脱颖而出,打破常规,让人眼前一亮,赞叹不已,从而升职加薪,迎娶白富美走向人生巅峰!看完这篇文档,保你的列表逼格满满。 接下来我们详细讲解一下如何实现

二、发展历史

这里我们不得不提一下列表符号的发展历史了 不喜欢历史的同学可以直接跳过

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

1. 数字和西方语系支持

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

例如:

css 复制代码
<ol type="A">
    <li>今天是个好日子</li>
    <li>风和日丽</li>
    <li>为什么我要加班</li>
    <li>我想回家睡觉</li>
    <li>写完这篇文章就回家</li>
</ol>

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

ini 复制代码
<ol type="1">
<ol type="a">
<ol type="A">
<ol type="i">
<ol type="I">

对应的序号如下图所示:

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

css 复制代码
/* 亚美尼亚 */
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 浏览器):

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

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

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

2. 其他语言系统的支持

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

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

比方说果孟加拉语(bengali)的序号就是下面这样的

其中,中日韩三国语言占据的项目符号类型高达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)。

例如"天干"可以实现甲乙丙丁序号效果:

然而问题又来了 世界上的国家那么多,一个国家可能还不止一个项目符号,国家里面还有部落,部落有自己的语言,怎么样,要不要支持?

不支持岂不是歧视那些小国,歧视这些部落与邦郡?说好的同住地球村,相亲相爱一家人,peace and love呢?

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

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

如果不支持,古人岂不是会有意见,你们这是歧视我们古人,不尊重历史!唾弃你!

好好好,既然你们这么玩,那就别怪我了。

让开,我要开始装X了!

我直接不和你们玩了,我给制定一套规范,你们去自己DIY,你们想怎么玩,就怎么玩,想用什么就用什么。

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

三、@counter-style

1. @counter-style语法

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

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

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

less 复制代码
@counter-style custom-style {}

而不是:

less 复制代码
@counter-style customStyle {}

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

具体的规则属性

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

首先,我们肯定要指定都需要哪些符号,但光指定符号明显自由度不够,而且逼格也不够高,还有什么呢?

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

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

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

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

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

1. system 属性

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

sql 复制代码
/* 关键字值 */
system: cyclic;
system: numeric;
system: alphabetic;
system: symbolic;
system: additive;
system: fixed;

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

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

cyclic

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

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

css 复制代码
@counter-style smile {
    system: cyclic;
    symbols: ☺;
    suffix: " ";
}
ul {
   list-style-type: smile;
}

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

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

css 复制代码
@counter-style even-odd {
    system: cyclic;
    symbols: 上 下;
    suffix: " ";
}
ul {
    list-style-type: even-odd;
}

此时项目符号就是上下不断循环,非特定场景下,几乎见不到使用

alphabetic

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

例如:

css 复制代码
@counter-style alphabetic {
    system: alphabetic;
    symbols: ⓐ ⓑ ⓒ;
    suffix: " ";
}
ul {
    list-style-type: alphabetic;
}

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

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

vbnet 复制代码
/* 无效 */
symbols: 1 2 3

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

如果是中文或者中文全角标点,则不需要加引号。另外需要注意的是symbols的值不需要,隔开。

numeric

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

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

效果示意:

css 复制代码
@counter-style numeric {
    system: numeric;
    symbols: ⓐ ⓑ ⓒ;
    suffix: " ";
}
ul {
    list-style-type: numeric;
}

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

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

fixed

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

例如:

css 复制代码
@counter-style fixed {
    system: fixed;
    symbols: ❶ ❷ ❸;
}
ul {
    list-style: fixed;
}

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

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

csharp 复制代码
system: fixed 3;

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

symbolic

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

例如:

css 复制代码
@counter-style symbolic {
    system: symbolic;
    symbols: ㊎ ㊍ ㊌ ㊋ ㊏;
}
ul {
    list-style: symbolic;
}

效果会是这样的,五行不断平铺重复。

additive

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

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

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

使用示意:

css 复制代码
@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 值特别适合超过一定序号,就突然改变字符显示的场景。

extends

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

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

css 复制代码
@counter-style october-comic {
    system: extends cjk-heavenly-stem;
    prefix: "[2023年11月新闻]";
    suffix: "、";
}
.extends {
    list-style: october-comic;
    padding-left: 8em;
}

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

四、关于 symbols 和 additive-symbols

1. symbols

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

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

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

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

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

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

css 复制代码
symbols: url('first.svg') url('second.svg') url('third.svg');

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

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

2. additive-symbols

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

css 复制代码
additive-symbols: 3 "0", 2 "1";

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

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

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

css 复制代码
/* 无效 */
additive-symbols:  2 "1", 3 "0";

举个例子,希望前3名使用冠军、亚军、季军、而不是1,2,3,4,5,则可以试试下面的代码(也可以使用 fixed 计数算法):

css 复制代码
@counter-style Olympic-draft {
    system: additive;
    additive-symbols: 季军 3, 亚军 2, 冠军 1;
    range: 1 3;
}
.draft {
    list-style-type: Olympic-draft;
}
xml 复制代码
<ul class="draft">
    <li>中国</li>
    <li>中国</li>
    <li>中国</li>
    <li>中国</li>
    <li>中国</li>
</ul>

就可以实现预期的效果:

五、前缀 prefix 和后缀 suffix

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

css 复制代码
prefix: ">>";
prefix: "▶";
prefix: "页码 ";
prefix: url(bullet.png);

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

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

六、pad 字符补全

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

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

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

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

语法

pad 属性语法示意:

css 复制代码
pad: 2 "0";

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

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

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

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

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

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

一些使用示意:

css 复制代码
range: infinite 10;

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

css 复制代码
range: infinite 6, 10 infinite;

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

例如下面这个代码:

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

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

八、兜底计数的fallback

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

还是 additive-symbols 属性这里用上面奥运的案例,如果我们在计数规则中增加这么一行 fallback 声明:

css 复制代码
@counter-style Olympic-draft {
    system: additive;
    additive-symbols: 季军 3, 亚军 2, 冠军 1;
    range: 1 3;
    fallback: cjk-decimal;
}
.draft {
    list-style-type: Olympic-draft;
}

第4项和第5项就不再是数字,而是遵守cjk-decimal

九、结语

怎么样兄弟们,是不是高级! 昨天搞得有点晚就睡觉了今天来了公司才发。转眼年底了,看着日益减少的头发,哎,今天又是讨厌的忙day,忙起来吧兄弟们。 奥利给!

相关推荐
2401_8827264827 分钟前
低代码配置式组态软件-BY组态
前端·物联网·低代码·前端框架·编辑器·web
web1309332039832 分钟前
ctfshow-web入门-文件包含(web82-web86)条件竞争实现session会话文件包含
前端·github
胡西风_foxww34 分钟前
【ES6复习笔记】迭代器(10)
前端·笔记·迭代器·es6·iterator
前端没钱37 分钟前
探索 ES6 基础:开启 JavaScript 新篇章
前端·javascript·es6
m0_748255261 小时前
vue3导入excel并解析excel数据渲染到表格中,纯前端实现。
前端·excel
土豆炒马铃薯。2 小时前
【Vue】前端使用node.js对数据库直接进行CRUD操作
前端·javascript·vue.js·node.js·html5
CC__xy2 小时前
Node二、Node.js 模块化、es6 软件包、Express - 框架
前端·node.js
zpjing~.~2 小时前
CSS 过渡动画效果
前端·css
Senar2 小时前
机器学习和前端
前端·人工智能·机器学习
GISer_Jing2 小时前
React基础知识(总结回顾一)
前端·react.js·前端框架