CSS 列表、标记和计数器

已发表: 2022-03-10
快速总结↬ CSS 中的样式列表比你想象的要多。 在本文中,Rachel 首先查看 CSS 中的列表,然后介绍 CSS 列表规范中定义的一些有趣的特性——标记和计数器。

CSS 中的列表具有特定的属性,这些属性为我们提供了我们期望的标准列表样式。 无序列表获得一个列表项目符号,类型为disc ,并且有序列表被编号。 我对更详细地探索列表的兴趣来自于我为 MDN 记录::marker伪元素所做的一些工作。 这个伪元素在 Firefox 68中发布,今天发布。 有了::marker伪元素,我们就可以开始用列表做一些有趣的事情了,在本文中,我将进行更多解释。

解构列表

尽管我们在标记中经常使用列表,但您可能没有过多考虑列表。 许多事情可以非常合乎逻辑地标记为列表。 虽然分步说明或排序元素可以自然地由有序列表<ol>描述,但设计中的许多事物都可以使用无序列表<ul>来描述。 例如,该元素的一个非常常见的用法是标记导航,因为它是网站上的目的地列表。 对于我们的探索,让我们首先找出 CSS 中的列表到底是什么。

与 CSS 中的许多东西一样,列表具有应用到它们的一些初始值。 这些值使它们看起来像一个列表。 这些特殊值以列表项具有值为list-itemdisplay属性的信息开头。 这将创建一个带有附加标记框的块级框。 标记框是添加列表项目符号或编号的位置。

跳跃后更多! 继续往下看↓

列表很早就在 CSS 中定义,我们今天使用的列表的大部分定义都来自 CSS2。 CSS2 规范对列表项的描述如下:

“具有display: list-item的元素会为元素的内容生成一个主要块框,并且根据list-style-typelist-style-image的值,还可能还有一个标记框作为元素的视觉指示一个列表项。”

主块框是元素的主框,包含所有子框,因为列表项可以包含其他标记。 然后相对于该主框放置标记框。 该规范继续详细说明任何背景颜色将仅在此主框后面,而不是标记后面。 此外,标记可以设置为一系列预定义值之一:

  • disc
  • circle
  • square
  • decimal
  • decimal-leading-zero
  • lower-roman
  • upper-roman
  • lower-greek
  • lower-latin
  • upper-latin
  • armenian
  • georgian
  • lower-alpha
  • upper-alpha
  • none
  • inherit

3 级显示规范定义了display: list-item以及display属性的其他可能值。 它引用了 CSS 2.1——就像许多来自 CSS2 的 CSS 属性和值一样——但将list-item关键字描述为“导致元素生成::marker伪元素”。

3 级规范还引入了使用display: inline list-item 。 这还没有被浏览器实现。

在非列表项上创建标记框

display的其他值一样,为任何 HTML 元素提供list-item的显示类型是完全有效的(如果您希望在项目上生成::marker伪元素)。 这不会导致元素在语义上成为列表项,而是只会在视觉上显示为列表项,因此能够具有::marker 。 当我们在下面讨论::marker伪元素时,您会发现在某些情况下给其他元素display: list-item可能很有用。

CSS Lists Level 3 Specification: ::marker和 Counters

display规范扩展并阐明了我们在 CSS2 中找到的列表的定义,但是,还有一个规范详细定义了列表行为:CSS 列表规范级别 3。由于列表项的基本行为在display中定义,因此规范详细说明了当某些东西具有display: list-item时生成的标记框以及在您创建有序列表时默认使用的计数器。 通过这些功能可以访问一些潜在有用的功能。

::marker伪元素

::marker伪元素允许您将列表标记作为目标——与列表项的内容分开。 这在以前的 CSS 版本中是不可能的,因此,如果您更改ulli的颜色或字体大小,这也会改变标记的颜色和字体大小。 为了做一些看似简单的事情,比如拥有与文本不同的颜色列表项目符号,将涉及将列表项的内容包装在一个跨度中(或使用图像作为标记)。

 ul { color: #00b7a8; } ul span { color #333; }

使用::marker伪元素,您可能想尝试的最简单的事情是使用与文本颜色不同的项目符号,这意味着您可以使用上面示例中的代码代替:

 ul { color: #333; } ul ::marker { color: #00b7a8; }

您可能还想为有序列表上的编号使用不同的大小和font-family

 ol ::marker { font-size: 200%; color: #00b7a8; font-family: "Comic Sans MS", cursive, sans-serif; }

您可以使用我的 CodePen 示例在支持的浏览器中查看所有这些内容:

请参阅 Rachel Andrew 的钢笔 [带和不带标记的彩色子弹](https://codepen.io/rachelandrew/penVJQyoR)。

请参阅 Rachel Andrew 的带有和不带标记的钢笔彩色子弹。

您可以在非列表项上使用::marker伪元素。 在下面的代码中,我设置了一个要display: list-item 。 这给了它一个项目符号,因此给它一个::marker框来定位。

我已将项目符号更改为使用表情符号:

 h1 { display: list-item; } h1::marker { content: ""; } 
标题左侧有一个猫表情符号
在 Firefox 中,您可以看到用作标记的表情符号。

请参阅 Rachel Andrew 的钢笔 [标题和标记](https://codepen.io/rachelandrew/pen/wLyyMG)。

请参阅 Rachel Andrew 的钢笔标题和标记。

在上面的示例中,我在标记的规则中使用了生成的内容。 只有一小部分 CSS 属性可用于::marker 。 这些包括字体属性和颜色,但是,它们还包括content属性,用于包含生成的内容。

content添加为::marker的允许属性是最近的,但是,它包含在 Firefox 实现中。 包含意味着您可以执行诸如在::marker中包含文本字符串之类的操作。 当您将计数器的使用与::marker结合使用时,它还为标记的格式提供了额外的可能性。

浏览器支持和回退

对于不支持::marker伪元素的浏览器,回退是无论如何都会显示的常规标记。 不幸的是,我们目前无法使用功能查询来检测对选择器的支持,例如这个伪元素,尽管已经提出了一个关于将其添加到规范中的问题。 这意味着当你得到支持时,你不能 fork 你的代码来做一件事,如果你没有,你就不能做别的事情。 在大多数情况下,回退到常规标记将是一个合理的解决方案。

计数器

有序列表具有列表编号——这是通过 CSS 计数器实现的。 因此,CSS 列表规范也描述了这些计数器。 我们可以自己访问和创建计数器,结合::marker伪元素可以为我们提供一些有用的功能。 这些计数器也可以用于常规(非::marker )生成的内容。

如果我有一个编号的步骤列表(并且我想写出“步骤 1”、“步骤 2”等),我可以通过在我的标记中使用生成的内容并附加list-item计数器来做到这一点,这代表内置计数器:

 ::marker { content: "Step " counter(list-item) ": "; } 
在每个列表项之前包含步骤 1、步骤 2 等的有序列表
在 Firefox 中,您会看到以“Step”为前缀的计数器。

请参阅 Rachel Andrew 的钢笔 [计数器和标记](https://codepen.io/rachelandrew/pen/BgRaoz)。

请参阅 Rachel Andrew 的钢笔计数器和记号笔。

嵌套计数器

如果您有嵌套列表,对它们进行编号的常用方法是让顶级项目为整数 (1),然后为子项目 (1.1, 1.2) 及其子项目 (1.1.1, 1.1.2),等等。 您可以通过使用计数器的更多功能来实现这一点。

当你嵌套 HTML 列表时,你最终会得到多个同名的计数器——相互嵌套。 可以使用counters()函数访问计数器的嵌套。

在下面的代码中,我使用counters()来格式化我的列表标记,如上所述。 counters()的第一个参数是要使用的计数器的名称。 我正在使用内置的list-item计数器。 第二个参数是一个字符串——这是将在输出计数器之间连接的内容(我使用的是. )。 最后,我在 counter 函数之外但在content的值内添加了一个: ,这样我的计数器输出将通过冒号与内容分开。

 ::marker { content: counters(list-item,'.') ':'; color: #00b7a8; font-weight: bold; }

这给了我图像中的输出。 如果您使用的浏览器支持::marker和计数器,那么您可以在 CodePen 示例中看到它的工作原理——尝试将字符串从. 到其他东西看看它是如何改变输出的。

一组嵌套列表
在 Firefox 中,您将看到由点分隔的嵌套列表编号。

请参阅 Rachel Andrew 的 Pen [嵌套计数器](https://codepen.io/rachelandrew/pen/VJbwxL)。

请参阅 Rachel Andrew 的 Pen Nested 计数器。

counter()counters()有什么区别?

我们在第一个示例中用于写出我们的步骤的counter()函数仅使用最里面的计数器。 因此,在您有一组嵌套列表的情况下,您将写出与您当前所在级别相关的计数器。

counters()函数本质上写出了整个分支,并让您有机会在分支中的计数器之间连接一个字符串。 因此,如果您有一个计数器为2的列表项(它是嵌套在计数器为4的列表项中的列表的一部分),则该分支包含:

  • 4
  • 2

您可以使用以下命令在标记中将其输出为4.2

 ::marker { content: counters(list-item,'.'); }

其他元素的计数器

计数器可以用于不是列表的东西——或者输出一个标记——在这种情况下,元素需要有display: list-item或者输出常规生成的内容。 计数器在书籍制作中被广泛使用,以使章节和图形编号数量更多。 没有理由不在网络上采取类似的方法,特别是对于较长的文章。

CSS 列表规范中定义的处理这些计数器的 CSS 属性是:

  • counter-set
  • counter-reset
  • counter-increment

要了解这些在列表之外是如何工作的,我们可以看一个使用计数器对文档中的标题进行编号的示例。

我需要做的第一件事是为 body 元素上的标题创建一个计数器——准备好使用。 我正在使用counter-reset属性来执行此操作。 counter-resetcounter-set属性非常相似。 如果指定名称的计数器不存在,则counter-reset属性将创建一个新的计数器,但如果该名称的计数器确实存在,也会创建如上所述的嵌套计数器。 如果没有该名称的计数器,则counter-set属性只会创建一个新的计数器。 为此,使用任一属性都可以正常工作,但是, counter-set的浏览器支持不如counter-reset ,所以我采取了实用的路线:

 body { counter-reset: heading-counter; }

现在我有了一个计数器,然后我可以在标题选择器上使用counter-increment属性; 这应该在每次选择器匹配时增加计数器。

 h2 { counter-increment: heading-counter; }

要查看该值,我需要将其输出到文档中。 我可以通过使用生成的内容并将其添加到标题before来做到这一点,如以下 CodePen 示例所示:

 h2::before { content: counter(heading-counter) ": "; color: #00b7a8; font-weight: bold; } 

请参阅 Rachel Andrew 的 Pen [标题和计数器](https://codepen.io/rachelandrew/pen/gNGjxq)。

请参阅 Rachel Andrew 的钢笔标题和计数器。

或者,我可以将h2元素变成一个list-item ,然后使用::marker ,如下所示。 如前所述,使用::marker元素的浏览器支持有限。 在 Firefox 中,您应该看到用作标题标记的计数器,而其他浏览器将显示默认项目符号。

 h2 { display: list-item; } h2::marker { content: counter(heading-counter) ": "; color: #00b7a8; font-weight: bold; } 

请参阅 Rachel Andrew 的 Pen [标题、标记和计数器](https://codepen.io/rachelandrew/pen/pXWZay)。

请参阅 Rachel Andrew 的钢笔标题、标记和计数器。

表单元素上的计数器

您还可以使用 CSS Counters 实现一些交互性——您可能认为需要 JavaScript 来完成。

我有一个包含许多必填字段的表单。 可以在 CSS 中使用:required伪类选择所需的状态,并且可以通过:invalid伪类检测字段尚未完成的事实。 这意味着我们可以检查必填和无效的字段,并增加一个计数器。 然后将其作为生成的内容输出。

请参阅 Rachel Andrew 的 Pen [Counting required form fields](https://codepen.io/rachelandrew/pen/vqpJdM)。

请参阅 Rachel Andrew 的 Pen Counting 必填表单字段。

这实际上有多大用处是值得商榷的——考虑到除了将其粘贴到生成的内容中之外,我们无法真正使用该值做任何事情。 还有人担心某些屏幕阅读器无法访问生成的内容,因此任何不仅仅是装饰性的使用都需要确保以其他方式访问该信息。 阅读“CSS 生成内容的辅助功能支持”和最新信息“CSS 内容属性屏幕阅读器兼容性”,了解有关辅助功能和生成内容的更多详细信息。

但是,它表明计数器可以实现比简单编号列表更有用的事情。 也许有一天,知识确实会派上用场,以解决您正在解决的问题。

了解更多

尽管我所描述的所有内容都可以在 CSS 列表规范中找到,但这篇文章与样式列表相去甚远。 您可以在下面的链接中找到有关所描述内容的更多信息。 如果您发现 CSS 计数器的有趣用途,或者可以想到可以使用::marker的东西,请在评论中添加注释。

  • ::marker
  • counter-set
  • counter-reset
  • counter-increment
  • “使用 CSS 计数器”,MDN 网络文档
  • “使用 CSS 计数器和 CSS 网格进行计数”,CSS 技巧