CSS 列表与计数器模块第 3 级

W3C 工作草案,

此版本
https://w3org.cn/TR/2020/WD-css-lists-3-20201117/
最新发布版本
https://w3org.cn/TR/css-lists-3/
编辑草案
https://drafts.csswg.org/css-lists-3/
历史版本
问题追踪
CSS 工作组问题仓库
文档内联
编辑
Elika J. Etemad / fantasai (特邀专家)
Tab Atkins (Google)
前任编辑
(Google)
(前 Microsoft 员工)
建议编辑此规范
GitHub 编辑器
贡献者
Simon Montagu, AOL-TW/Netscape, smontagu@netscape.com
Daniel Yacob, yacob@geez.org
Christopher Hoess, choess@stwing.upenn.edu
Daniel Glazman, AOL-TW/Netscape, glazman@netscape.com

摘要

本模块包含与列表计数器相关的 CSS 特性:设置其样式、定位以及操作其值。

CSS 是一种用于描述结构化文档(如 HTML 和 XML)在屏幕、纸张等介质上渲染方式的语言。

关于本文档

本节描述了本文件发布时的状态。其他文件可能会取代本文件。W3C 当前出版物列表和本技术报告的最新修订版本可在 https://w3org.cn/TR/ 的 W3C 技术报告索引中找到。

本文档由 CSS 工作组发布为工作草案。作为工作草案发布并不代表 W3C 会员的认可。

这是一份草案文档,可能会随时被其他文档更新、替换或废弃。将其作为非进行中工作引用是不恰当的。

请通过在 GitHub 上提交 issue(推荐)发送反馈,标题需包含规范代码“css-lists”,格式如下:“[css-lists] ……评论摘要……”。所有 issue 和评论均已存档。或者,也可以将反馈发送至(已存档的)公共邮件列表 www-style@w3.org

本文档受 2020年9月15日版 W3C 流程文档 约束。

本文档由在一个组织下运作的小组制作,该组织遵循 W3C 专利政策。W3C 维护着一份与小组可交付成果相关的专利披露公开列表;该页面还包含披露专利的说明。任何知晓某项专利包含必要权利要求 (Essential Claim) 的个人,必须按照 W3C 专利政策第 6 节披露相关信息。

1. 简介

本规范定义了 ::marker 伪元素、生成标记的 list-item 显示类型,以及用于控制标记放置和样式的若干属性。

它还定义了 计数器 (counters),这是一种特殊的数值对象,常用于生成标记的默认内容。

例如,以下示例展示了如何利用标记在每个编号列表项周围添加括号。
<style>
li::marker { content: "(" counter(list-item, lower-roman) ")"; }
li { display: list-item; }
</style>
<ol>
  <li>This is the first item.
  <li>This is the second item.
  <li>This is the third item.
</ol>

它应产生类似于以下的效果

  (i) This is the first item.
 (ii) This is the second item.
(iii) This is the third item.

注意: 请注意,此示例在 HTML 中比通常需要的要繁琐得多,因为 UA 的默认样式表已经处理了大部分必要的样式。

通过后代选择器和子选择器,可以根据嵌套列表的深度指定不同的标记类型。

1.1. 值定义

本规范遵循 CSS 属性定义约定[CSS2]),使用 值定义语法[CSS-VALUES-3])。本规范未定义的值类型在 CSS Values & Units [CSS-VALUES-3] 中定义。与其他 CSS 模块的组合可能会扩展这些值类型的定义。

除了定义中列出的属性特定值外,本规范中定义的所有属性也都接受 CSS 全局关键字 作为其属性值。为了可读性,未明确重复列出。

2. 声明列表项

列表项 (list item) 是指任何将其 display 属性设置为 list-item 的元素。列表项会生成 ::marker 伪元素;其他元素则不会。此外,列表项会自动递增一个隐式的 list-item 计数器(参见 § 4.6 隐式 list-item 计数器)。

3. 标记 (Markers)

列表项 显示类型的定义特征是其 标记 (marker),即有助于表示列表中每个列表项开头的符号或序数。在 CSS 布局模型中,列表项 标记由与每个列表项相关联的标记框 (marker box)表示。此标记的内容可以通过列表项上的 list-style-typelist-style-image 属性进行控制,也可以通过为其 ::marker 伪元素分配属性来控制。

3.1. ::marker 伪元素

标记框列表项::marker 伪元素生成,作为列表项的第一个子元素,位于 ::before 伪元素之前(如果该元素上存在此伪元素)。其填充内容由 § 3.2 生成标记内容定义。

在本示例中,标记用于对指定为“注”的段落进行编号
<style>
p { margin-left: 12 em; }
p.note {
  display: list-item;
  counter-increment: note-counter;
}
p.note::marker {
  content: "Note " counter(note-counter) ":";
}
</style>
<p>This is the first paragraph in this document.
<p class="note">This is a very short document.
<p>This is the end.

它应渲染出类似于以下的效果

        This is the first paragraph
        in this document.

Note 1: This is a very short
        document.

        This is the end.
通过使用 ::marker 伪元素,列表标记的样式可以独立于列表项本身的文本进行设置
<style>
p { margin-left: 8em } /* Make space for counters */
li { list-style-type: lower-roman; }
li::marker { color: blue; font-weight:bold; }
</style>
<p>This is a long preceding paragraph ...
<ol>
  <li>This is the first item.
  <li>This is the second item.
  <li>This is the third item.
</ol>
<p>This is a long following paragraph ...

前面的文档应渲染出类似于以下的效果

       This is a long preceding
       paragraph ...

  i.   This is the first item.
 ii.   This is the second item.
iii.   This is the third item.

       This is a long following
       paragraph ...

以前,设置标记样式的唯一方法是通过继承;用户必须在列表项上放置所需的标记样式,然后在列表项实际内容的包装元素上还原该样式。

标记框仅针对列表项存在:对于任何其他元素,::marker 伪元素的 content 属性必须计算为 none,这会抑制其创建。

3.1.1. 适用于 ::marker 的属性

所有属性都可以设置在 ::marker 伪元素上,并将具有 计算值;然而,实际上只有以下 CSS 属性适用于 标记框

预期未来的规范将扩展此属性列表;但目前由于尚未完全定义外部标记框布局,因此仅允许使用这些属性。

当在级联作者源 (author origin)中设置时,其他属性不得对标记框产生影响。UA 可以将此类属性视为不适用,或通过设置用户代理源 (user-agent origin)!important 规则来强制执行其值。但是,适用于文本的可继承属性可以设置在 ::marker 伪元素上:这些属性将继承并作用于其文本内容。

当在 ::marker 上声明时,适用于文本(从而适用于 ::marker 内容)的属性示例

UA 必须在默认样式表中添加以下规则

::marker, ::before::marker, ::after::marker {
  unicode-bidi: isolate;
  font-variant-numeric: tabular-nums;
  white-space: pre;
  text-transform: none;
}

注意: 虽然 ::marker 伪元素可以代表 ::before::after 伪元素的标记框,但复合选择器 ::marker(扩展为 *::marker [SELECTORS-4])不会选择这些标记——必须在选择器中显式指定作为伪元素原始元素,例如 ::before::marker

white-space: pre 的行为不完全正确;text-space-collapse: preserve-spaces + text-space-trim: discard-after 可能更接近此处所需的功能。请参阅 Issue 4448Issue 4891 中的讨论。

3.2. 生成标记内容

标记框的内容由以下第一个为真的条件决定

::marker 本身的 content 不为 normal
标记框的内容由 content 属性定义,与 ::before 完全相同。
原始元素上的 list-style-image 定义了一个 标记图像
标记框包含一个代表指定标记图像匿名行内替换元素,后跟一个由单个空格(U+0020 SPACE)组成的文本运行 (text run)
原始元素上的 list-style-type 定义了一个 标记字符串
标记框包含一个由指定的标记字符串组成的文本运行
否则
标记框没有任何内容,且 ::marker 不生成框。

此外,UA 可以将任何保留的强制换行符转换为空格或将其丢弃。

3.3. 图像标记:list-style-image 属性

名称list-style-image
<image> | none
初始值 none(无)
应用于列表项
可继承
百分比 不可用
计算值 关键字 none 或计算出的 <image>
规范顺序按语法
动画类型 离散 (discrete)

指定标记图像,当其 contentnormal 时,用于填充列表项标记。其值如下

<image>
如果 <image> 代表一个有效图像,则将元素的标记图像指定为该 <image>。否则,该元素没有标记图像
none(无)
该元素没有标记图像
以下示例将每个列表项开头的标记设置为图像“ellipse.png”。
li { list-style-image: url("http://www.example.com/ellipse.png") }

3.4. 文本标记:list-style-type 属性

名称list-style-type
<counter-style> | <string> | none
初始值 disc
应用于列表项
可继承
百分比 不可用
计算值 指定的值
规范顺序按语法
动画类型 离散 (discrete)

指定标记字符串,当其 content 值为 normal 且没有标记图像时,用于填充列表项标记。其值如下

<counter-style>
指定元素的标记字符串为使用指定的 <counter-style> 表示的 list-item 计数器的值。

具体而言,标记字符串是使用指定的 <counter-style> 生成计数器表示 list-item 计数器值的结果,前缀为 <counter-style>prefix,后缀为 <counter-style>suffix。如果指定的 <counter-style> 不存在,则默认为 decimal

<string>
元素的标记字符串为指定的 <string>
none
该元素没有标记字符串
以下示例展示了如何将标记设置为各种值
ul { list-style-type: "★"; }
/* Sets the marker to a "star" character */

p.note {
  display: list-item;
  list-style-type: "Note: ";
  list-style-position: inside;
}
/* Gives note paragraphs a marker consisting of the string "Note: " */

ol { list-style-type: upper-roman; }
/* Sets all ordered lists to use the upper-roman counter-style
   (defined in the Counter Styles specification [[CSS-COUNTER-STYLES]]) */

ul { list-style-type: symbols(cyclic '○' '●'); }
/* Sets all unordered list items to alternate between empty and
   filled circles for their markers. */

ul { list-style-type: none; }
/* Suppresses the marker entirely, unless list-style-image is specified
   with a valid image. */

3.5. 定位标记:list-style-position 属性

名称list-style-position
inside | outside
初始值 outside (外侧)
应用于列表项
可继承
百分比 不可用
计算值 关键字,但请参阅正文
规范顺序按语法
动画类型 离散 (discrete)

此属性决定 ::marker 是作为行内元素渲染,还是定位在列表项的正外部。其值如下

inside (内侧)
无特殊效果。(::marker 是位于列表项内容开头的行内元素。)
outside (外侧)
如果列表项是一个块容器:标记框是一个块容器,并放置在主块框之外;然而,邻近浮动元素的列表项标记的位置未定义。CSS 未指定标记框的精确位置或其在绘制顺序中的位置,但确实要求将其放置在盒子的行内起始 (inline-start)侧,使用由 marker-side 指示的盒子书写模式 (writing mode)。标记框相对于主块框的边框是固定的,且不随主块框的内容滚动。如果元素的 overflow 不是 visible,UA 可能会隐藏标记。(此规定在未来可能会改变。)标记框的大小或内容可能会影响主块框的高度和/或其第一行框的高度,并在某些情况下可能导致创建新的行框;此交互也未定义。

这是来自 CSS2 的模糊表述,需要一个真实的定义。

如果列表项是一个行内框:此值等同于 inside

或者,outside 可以将标记布局为前一个主行内框的兄弟节点。

例如
<style>
  ul.compact { list-style: inside; }
  ul         { list-style: outside; }
</style>
<ul class=compact>
  <li>first "inside" list item comes first</li>
  <li>second "inside" list item comes first</li>
</ul>
<hr>
<ul>
  <li>first "outside" list item comes first</li>
  <li>second "outside" list item comes first</li>
</ul>

上述示例可以格式化为

  * first "inside" list
  item comes first
  * second "inside" list
  item comes second

========================

* first "outside" list
  item comes first
* second "outside" list
  item comes second

3.6. 设置标记样式:list-style 简写属性

名称list-style
<'list-style-position'> || <'list-style-image'> || <'list-style-type'>
初始值 见各个属性
应用于列表项
可继承 见各个属性
百分比 见各个属性
计算值 见各个属性
动画类型 见各个属性
规范顺序按语法

list-style 属性是一个简写符号,用于在样式表的同一位置设置 list-style-typelist-style-imagelist-style-position 这三个属性。

例如
ul { list-style: upper-roman inside }  /* Any UL */
ul ul { list-style: circle outside } /* Any UL child of a UL */

在简写属性中使用 none 值可能会产生歧义,因为 nonelist-style-imagelist-style-type 属性的有效值。为了消除这种歧义,简写属性中的 none 值必须应用于尚未由简写属性设置的这两个属性中的任意一个。

list-style: none disc;
/* Sets the image to "none" and the type to "disc". */

list-style: none url(bullet.png);
/* Sets the image to "url(bullet.png)" and the type to "none". */

list-style: none;
/* Sets both image and type to "none". */

list-style: none disc url(bullet.png);
/* Syntax error */

注意: list-style-type<counter-style> 值也会产生语法歧义。由于此类值最终是 <custom-ident> 值,因此适用 [CSS-VALUES-3] 中的解析规则。

虽然作者可以直接在列表项元素(例如 HTML 中的 li)上指定 list-style 信息,但应小心使用。考虑以下规则
ol.alpha li { list-style: lower-alpha; }
ul li       { list-style: disc; }

上述做法不会按预期工作。如果你在 ol class=alpha 中嵌套了一个 ul,第一个规则的特指度 (specificity) 将使 ul 的列表项使用 lower-alpha 样式。

ol.alpha > li { list-style: lower-alpha; }
ul > li       { list-style: disc; }

这些按预期工作。

ol.alpha { list-style: lower-alpha; }
ul       { list-style: disc; }

这些更好,因为继承会将 list-style 值传递给列表项。

3.7. marker-side 属性

名称marker-side
match-self | match-parent
初始值 match-self
应用于列表项
可继承
百分比 不可用
计算值 指定关键字
规范顺序按语法
动画类型 离散 (discrete)

marker-side 属性指定outside 标记框是根据列表项本身(即其原始元素)的方向性来定位,还是根据列表容器(即原始元素的父元素)的方向性来定位。在前一种情况下,标记的位置可能因列表中的不同项目而异,取决于为每个列表项单独分配的方向性;在后一种情况下,它们都将对齐在同一侧,由为整个列表分配的方向性决定。

match-self
标记框使用 ::marker原始元素的方向性进行定位。
match-parent
标记框使用 ::marker原始元素的父元素的方向性进行定位。
默认情况下,元素或 ::marker 伪元素根据列表项的方向性自行定位。然而,如果列表项与具有不同方向性的其他若干列表项组合在一起(例如,HTML 中
    内带有不同“dir”属性的多个
  1. ),有时将所有标记对齐在同一侧会更有用,这样作者可以在该侧指定单一的“槽 (gutter)”,并确保所有标记都位于该槽中并且可见。

    以下两个渲染示例均由相同的 HTML 生成,唯一的区别是列表上 marker-side 的值

    <ul>
      <li>english one
      <li dir=rtl>OWT WERBEH
      <li>english three
      <li dir=rtl>RUOF WERBEH
    </ul>
    
    match-self match-parent
    * english one
         OWT WERBEH *
    * english three
        RUOF WERBEH *
    * english one
    *    OWT WERBEH
    * english three
    *   RUOF WERBEH

为了使该顺序标点符号正确地位于标记内部,它还需要获取父元素的 direction 值。<https://github.com/w3c/csswg-drafts/issues/4202>

关于重命名关键字以及list-style-position 合并的问题均处于开放状态。

4. 使用计数器进行自动编号

一个 计数器 (counter) 是一种特殊的数值跟踪器,除其他用途外,还用于自动对 CSS 中的列表项进行编号。每个元素都有一组零个或多个计数器,它们以类似于继承属性值的方式通过文档树进行继承。计数器具有一个 名称 (name)创建者 (creator)(用于识别计数器),以及一个整数 值 (value)。它们使用 计数器属性 counter-increment, counter-setcounter-reset 进行创建和操作,并与 counter()counters() 函数符号 (functional notations) 一起使用。

计数器在 CSS 语法中使用 <counter-name> 类型进行引用,该类型将其名称表示为 <custom-ident><counter-name> 名称不能匹配关键字 none;作为 <counter-name>,此类标识符是无效的

在给定元素上解析计数器值是一个多步骤过程

  1. 现有的计数器从前一个元素继承而来。

  2. 新的计数器被实例化 (counter-reset)。

  3. 计数器值被递增 (counter-increment)。

  4. 计数器值被显式设置 (counter-set)。

  5. 计数器值被使用 (counter()/counters())。

UA 可能对计数器的最大值或最小值有实现相关的限制。如果计数器的重置、设置或递增会导致值超出该范围,则该值必须被钳制在该范围内。

4.1. 创建计数器:counter-reset 属性

名称counter-reset
[ <counter-name> <integer>? ]+ | none
初始值 none(无)
应用于所有元素
可继承
百分比 不可用
计算值 关键字 none 或一个列表,其中每一项是一个与整数配对的标识符
规范顺序按语法
动画类型 按计算值类型

用户代理应在所有媒体(包括非视觉媒体)上支持此属性。

counter-reset 属性在元素上实例化新的计数器,并将它们设置为指定的整数值。其值定义如下

none(无)
此元素不创建任何新计数器。
<counter-name> <integer>?
实例化一个给定 <counter-name> 的计数器,起始值为给定的 <integer>,默认为 0
请注意,计数器属性遵循级联规则。因此,由于级联,以下样式表
h1 { counter-reset: section -1 }
h1 { counter-reset: imagenum 99 }

将仅重置 imagenum。要重置两个计数器,必须将它们一起指定

H1 { counter-reset: section -1 imagenum 99 }

同样的原则也适用于 counter-setcounter-increment 属性。请参阅 [css-cascade-4]

如果属性值中出现多个相同的 <counter-name>,仅最后一个会被采纳。

4.2. 操作计数器值:counter-incrementcounter-set 属性

名称counter-increment
[ <counter-name> <integer>? ]+ | none
初始值 none(无)
应用于所有元素
可继承
百分比 不可用
计算值 关键字 none 或一个列表,其中每一项是一个与整数配对的标识符
规范顺序按语法
动画类型 按计算值类型

用户代理应在所有媒体(包括非视觉媒体)上支持此属性。

名称counter-set
[ <counter-name> <integer>? ]+ | none
初始值 none(无)
应用于所有元素
可继承
百分比 不可用
计算值 关键字 none 或一个列表,其中每一项是一个与整数配对的标识符
规范顺序按语法
动画类型 按计算值类型

用户代理应在所有媒体(包括非视觉媒体)上支持此属性。

counter-incrementcounter-set 属性操作现有计数器的值。它们仅在元素上尚不存在给定名称的计数器时才会实例化新计数器。其值定义如下

none
此元素不更改任何计数器的值。
<counter-name> <integer>?
设置(对于 counter-set)或递增(对于 counter-increment)元素上命名计数器的值,增量/设定为指定的 <integer>。如果省略 <integer>,则默认为 1(对于 counter-increment)或 0(对于 counter-set)。

如果元素上当前不存在给定名称的计数器,该元素在设置或递增其值之前,会实例化一个给定名称且起始值为 0 的新计数器。

以下示例展示了如何使用 “Chapter 1”、 “1.1”、 “1.2” 等方式为章节与小节编号。

h1::before {
    content: "Chapter " counter(chapter) ". ";
    counter-increment: chapter;  /* Add 1 to chapter */
    counter-reset: section;      /* Set section to 0 */
}
h2::before {
    content: counter(chapter) "." counter(section) " ";
    counter-increment: section;
}

如果属性值中出现多个相同的 <counter-name>,则它们会按顺序全部处理。因此递增会复合,但仅最后一个设定值生效。

4.3. 嵌套计数器与作用域

计数器是“自嵌套”的;在一个从其父元素继承了同名计数器的元素上实例化一个新计数器,会创建一个同名的新计数器,嵌套在现有计数器内部。这对于 HTML 中的列表等情况很重要,因为列表可以嵌套在任意深度的列表中:为每一层定义唯一命名的计数器是不可能的。counter() 函数仅检索元素上给定名称的最内层计数器,而 counters() 函数则使用所有包含该元素的给定名称的计数器。

因此,计数器作用域 (scope) 从文档中第一个实例化该计数器的元素开始,并包括该元素的后代及其后续兄弟元素及其后代。但是,它不包括由该元素后续兄弟元素上的 counter-reset 创建的同名计数器的作用域中的任何元素,从而允许此类显式计数器实例化掩盖那些较早的兄弟元素。

请参阅 § 4.4 创建与继承计数器,了解管辖计数器作用域及其值的确切规则。

以下代码对嵌套列表项进行编号。结果与在 LI 元素上设置 display:list-itemlist-style: inside 的结果非常相似
ol { counter-reset: item }
li { display: block }
li::before { content: counter(item) ". "; counter-increment: item }

在此示例中,ol 将创建一个计数器,并且该 ol 的所有子元素都将引用该计数器。

如果我们用 itemn 表示 item 计数器的第 n 个实例,那么以下 HTML 片段将使用所指示的计数器。

<ol> 创建 item0,设置为 0
<li> item0 递增为 1
<li> item0 递增为 2
<ol> 创建 item1,设置为 0,嵌套在 item0
<li> item1 递增为 1
<li> item1 递增为 2
<li> item1 递增为 3
<ol> 创建 item2,设置为 0,嵌套在 item1
<li> item2 递增为 1
</ol>
<li> item1 递增为 4
<ol> 创建 item3,设置为 0,嵌套在 item1
<li> item3 递增为 1
</ol>
<li> item1 递增为 5
</ol>
<li> item0 递增为 3
<li> item0 递增为 4
</ol>
<ol> 创建 item4,设置为 0
<li> item4 递增为 1
<li> item4 递增为 2
</ol>

4.4. 创建与继承计数器

文档中的每个元素或伪元素在其作用域内都有一组(可能为空)计数器,要么通过从另一个元素继承,要么通过直接在元素上进行实例化。这些计数器表示为 CSS 计数器集合 (CSS counters set),这是一个 集合,其值均为 元组 (tuple):一个 字符串(代表计数器的名称)、一个元素(代表计数器的创建者)以及一个整数(代表计数器的)。该集合中给定名称的最新计数器代表该名称的最内层计数器。

4.4.1. 继承计数器

元素从其父元素和前面的兄弟元素继承其初始计数器集合。然后,它从其树序 (tree order) 中的前一个元素(可能是其父元素、其前一个兄弟元素,或其前一个兄弟元素的后代)的匹配计数器值中获取这些计数器的值。若要将计数器继承element
  1. 如果 element 是其文档树的根 (root),则该元素具有一个初始为空的 CSS 计数器集合。返回。

  2. element counters(表示 element 自身的 CSS 计数器集合)为 element 父元素的 CSS 计数器集合的副本。

  3. sibling counterselement 前一个兄弟元素(如果有)的 CSS 计数器集合,否则为一个空的 CSS 计数器集合

    对于 sibling counters 中的每个 counter,如果 element counters 尚不包含名称相同的计数器,则将 counter 的副本追加到 element counters 中。

  4. value source 为在树序中紧邻 element 之前的元素的 CSS 计数器集合

    对于 value source 中的每个 source counter,如果 element counters 包含一个名称和创建者相同的计数器,则将该计数器的设置为 source counter

以以下代码为例
<ul style='counter-reset: example 0;'>
  <li id='foo' style='counter-increment: example;'>
    foo
    <div id='bar' style='counter-increment: example;'>bar</div>
  </li>
  <li id='baz'>
    baz
  </li>
</ul>

回想一下,树序将文档树转换为有序列表,其中元素出现在其子元素之前,而子元素出现在其下一个兄弟元素之前。换句话说,对于像 HTML 这样的语言,它是解析器在读取文档时遇到开始标签的顺序。

在这里,ul 元素建立了一个名为 example 的新计数器,并将其值设置为 0。作为 ul 的第一个子元素,#foo 元素继承了此计数器。其父元素也是其在树序中紧邻的前一个元素,因此它随之继承了值 0,然后立即将该值递增为 1

#bar 元素也是如此。它从 #foo 继承了 example 计数器,同时也从其继承了值 1 并将其递增为 2

然而,#baz 元素略有不同。它从其前一个兄弟元素 #foo 继承了 example 计数器。但是,它并没有随计数器一起从 #foo 继承值 1,而是从树序中的前一个元素 #bar 继承了值 2

这种行为允许在整个文档中使用单个计数器,持续递增,而作者无需担心文档的嵌套结构。

注意: 计数器继承与常规 CSS 继承一样,在 [DOM] 上下文中的“扁平化元素树”上操作。

4.4.2. 实例化计数器

计数器counter-reset 中命名时会被实例化,当在 counter-incrementcounter-setcounter()counters() 符号中命名但尚未存在时,也会被实例化。(新实例化计数器会替换源自前一个兄弟元素的同名计数器,但除了源自祖先元素的同名计数器之外还会被添加,请参阅 § 4.3 嵌套计数器与作用域。)若要在一个element上以起始value实例化一个计数器(名称为 name
  1. counterselementCSS 计数器集合

  2. innermost countercounters 中名称为 name 的最后一个计数器。如果 innermost counter 的原始元素是 elementelement 的前一个兄弟元素,则从 counters移除 innermost counter

  3. 追加一个新计数器counters 中,其名称为 name,原始元素为 element,初始值为 value

4.5. 不生成框的元素中的计数器

不生成框的元素(例如,display 设置为 none 的元素,或者 content 设置为 none 的伪元素)不能设置、重置或递增计数器。计数器属性在此类元素上仍然有效,但它们必须不产生任何影响。

例如,在以下样式表中,类为“secret”的 H2 元素不会递增 count2
h2 { counter-increment: count2; }
h2.secret { display: none; }

注意: 其他“隐藏”元素的方法,例如将 visibility 设置为 hidden,仍然会导致元素生成框,因此此处不予排除。

是否替换元素的后代(例如 HTML option 或 SVG rect)可以设置、重置或递增计数器尚不明确。

注意: 由于不同实现间缺乏互操作性,替换元素后代的行为目前未定义。

4.6. 隐式 list-item 计数器

除了作者在样式中编写的任何显式定义的计数器外,列表项还会自动递增一个特殊的 list-item 计数器,该计数器用于在列表项上生成默认的标记字符串(参见 list-style-type)。

具体而言,除非 counter-increment 属性显式为 list-item 计数器指定了不同的增量,否则它必须在每个列表项上递增 1,同时在计数器正常递增时递增(完全就像列表项counter-increment 值被追加了 list-item 1 一样,包括副作用,例如可能实例化一个新的计数器等)。这不会影响 counter-increment指定值计算值

因为每个 列表项 (list item) 都会自动将 list-item 计数器加 1,所以默认情况下,具有数字型 list-style-type 的连续 列表项 将会被连续编号——即使作者将 counter-increment 设置为其他值,例如 counter-increment: itemnumber,甚至是 none。这可以保护自动的 list-item 计数器不会被旨在处理其他计数器的声明无意中覆盖。

然而,由于如果 列表项counter-increment 显式提到了 list-item 计数器,则自动的 list-item 递增不会发生,因此 li { counter-increment: list-item 2; } 会按规定将 list-item 增加 2,而不是像无条件追加 list-item 1 那样增加 3。

这也允许通过显式覆盖来关闭自动的 list-item 计数器递增,例如 counter-increment: list-item 0;

在所有其他方面,list-item 计数器 的行为与其他任何 计数器 相同,并且可以被作者使用和操作,以调整 列表项 样式或用于其他目的。

在以下示例中,列表被修改为以二为单位进行计数

ol.evens > li { counter-increment: list-item 2; }

一个三项列表将被渲染为

2. First Item
4. Second Item
6. Third Item

用户代理 (UA) 和宿主语言应确保在用户代理样式表和表现提示样式映射中设置列表项样式时,默认的 list-item 计数器值反映了宿主语言语义所决定的潜在数值。参见,例如 附录 A:HTML 示例样式表

在以下示例中,content 属性用于创建连接到 list-item 计数器的分层编号,从而遵守通过 HTML 实施的任何编号更改
ol > li::marker { content: counters(list-item,'.') '.'; }

使用此规则的嵌套列表将被渲染为

1. First top-level item
5. Second top-level item, value=5
   5.3. First second-level item, list start=3
   5.4. Second second-level item, list start=3
        5.4.4. First third-level item in reversed list
        5.4.3. Second third-level item in reversed list
        5.4.2. Third third-level item in reversed list
        5.4.1. Fourth third-level item in reversed list
   5.5. Third second-level item, list start=3
6. Third top-level item

给定如下标记

<ol>
  <li>First top-level item
  <li value=5>Second top-level item, value=5
    <ol start=3>
      <li>First second-level item, list start=3
      <li>Second second-level item, list start=3
        <ol reversed>
          <li>First third-level item in reversed list
          <li>Second third-level item in reversed list
          <li>Third third-level item in reversed list
          <li>Fourth third-level item in reversed list
        </ol>
    </ol>
  <li>Third second-level item, list start=3
  <li>Third top-level item
</ol>

4.7. 输出计数器:counter()counters() 函数

计数器 本身没有可见效果,但其值可以与 counter()counters() 函数一起使用,这些函数的 使用值 (used values) 将计数器值表示为字符串或图像。它们定义如下

<counter> = <counter()> | <counters()>
counter()  =  counter( <counter-name>, <counter-style>? )
counters() = counters( <counter-name>, <string>, <counter-style>? )

其中 <counter-style> 指定了 计数器样式,用于 生成 命名计数器的表示形式,如 [css-counter-styles-3] 中所定义,并且

counter()
表示元素 CSS 计数器集合 中名为 <counter-name>最内层 计数器 的值,使用名为 <counter-style>计数器样式
counters()
表示元素 CSS 计数器集合 中所有名为 <counter-name>计数器 的值,使用名为 <counter-style>计数器样式,按从最外层到 最内层 的顺序排序,并由指定的 <string> 连接。

在这两种情况下,如果省略 <counter-style> 参数,则默认为 decimal

如果在某个元素上使用了 counter()counters(),但该元素上不存在名为 <counter-name>计数器,则首先 实例化 一个起始值为 0 的计数器。

H1::before        { content: counter(chno, upper-latin) ". " }
/* Generates headings like "A. A History of Discontent" */

H2::before        { content: counter(section, upper-roman) " - " }
/* Generates headings like "II - The Discontent Part" */

BLOCKQUOTE::after { content: " [" counter(bq, decimal) "]" }
/* Generates blockquotes that end like "... [3]" */

DIV.note::before  { content: counter(notecntr, disc) " " }
/* Simply generates a bullet before every div.note */

P::before         { content: counter(p, none) }
/* inserts nothing */
以下示例展示了 counters() 函数的简单用法
<ul>
  <li>one</li>
  <li>two
    <ul>
      <li>nested one</li>
      <li>nested two</li>
    </ul>
  </li>
  <li>three</li>
</ul>
<style>
li::marker { content: '(' counters(list-item,'.') ') '; }
</style>

前面的文档应渲染出类似于以下的效果

(1) one
(2) two
   (2.1) nested one
   (2.2) nested two
(3) three
由于计数器也会继承到兄弟元素,因此它们可以用于对标题和子标题进行编号,即使它们没有相互嵌套。不幸的是,这妨碍了 counters() 的使用,因为来自兄弟元素的计数器不会嵌套,但可以创建多个计数器并手动连接它们
<h1>First H1</h1>
...
<h2>First H2 in H1</h2>
...
<h2>Second H2 in H1</h2>
...
<h3>First H3 in H2</h3>
...
<h1>Second H1</h1>
...
<h2>First H2 in H1</h2>
...
<style>
body { counter-reset: h1 h2 h3; }
h1   { counter-increment: h1; counter-reset: h2 h3;}
h2   { counter-increment: h2; counter-reset:    h3; }
h3   { counter-increment: h3; }
h1::before { content: counter(h1,upper-alpha) ' '; }
h2::before { content: counter(h1,upper-alpha) '.'
                      counter(h2,decimal) ' '; }
h3::before { content: counter(h1,upper-alpha) '.'
                      counter(h2,decimal) '.'
                      counter(h3,lower-roman) ' '; }
</style>

前面的文档应渲染出类似于以下的效果

A First H1
...
A.1 First H2 in H1
...
A.2 Second H2 in H1
...
A.2.i First H3 in H2
...
B Second H1
...
B.1 First H2 in H1
...
计数器有时不仅对于打印标记有用。总的来说,它们提供了按顺序编号元素的能力,这对于其他属性的引用非常有用。例如,使用 order 将一个元素放在其他两个特定元素之间,目前要求您在所需插入点之前和/或之后的所有元素上显式设置 order。不过,如果您可以将所有内容的 order 值设置为计数器,那么您可以更轻松地将元素插入到其他两个元素之间的任意位置。

其他用例涉及带有相互之间略有不同的变换(transforms)的嵌套或兄弟元素。目前,您必须使用预处理器以合理的方式执行此操作,但计数器将使其在“普通”CSS 中良好运行。

(您目前可以通过使用 自定义属性 和堆叠嵌套的 calc() 来构建嵌套情况下的连续值,但这稍微有点笨拙,并且不适用于兄弟元素。)

建议添加一个 counter-value(<counter-name>) 函数,它返回命名计数器的值作为整数,而不是返回字符串。

参见 问题 1026

附录 A:HTML 示例样式表

本节仅供参考,不具规范性。[HTML] 渲染 章节定义了适用于 HTML 列表的规范默认属性;提供此示例样式表是为了说明使用熟悉的标记惯例的 CSS 特性。

关于如何在 CSS 中支持 ol[reversed] 列表编号的讨论正在进行中。参见,例如 问题 4181

/* Set up list items */
li {
  display: list-item; /* implies 'counter-increment: list-item' */
}

/* Set up ol and ul so that they scope the list-item counter */
ol, ul {
  counter-reset: list-item;
}

/* Default list style types for lists */
ol { list-style-type: decimal; }
ul { list-style-type: toggle(disc, circle, square); }

/* The type attribute on ol and ul elements */
ul[type="disc"]   { list-style-type: disc;   }
ul[type="circle"] { list-style-type: circle; }
ul[type="square"] { list-style-type: square; }
ol[type="1"] { list-style-type: decimal;     }
ol[type="a"] { list-style-type: lower-alpha; }
ol[type="A"] { list-style-type: upper-alpha; }
ol[type="i"] { list-style-type: lower-roman; }
ol[type="I"] { list-style-type: upper-roman; }

/* The start attribute on ol elements */
ol[start] {
  counter-reset: list-item calc(attr(start integer, 1) - 1);
}

/* The value attribute on li elements */
li[value] {
  counter-set: list-item attr(value integer, 1);
}


/* Box Model Rules */
ol, ul {
  display: block;
  margin-block: 1em;
  marker-side: match-parent;
  padding-inline-start: 40px;
}
ol ol, ol ul, ul ul, ul ol {
  margin-block: 0;
}

li {
  text-align: match-parent;
}

致谢

本规范的实现得益于 Aharon Lanin, Arron Eicholz, Brad Kemper, David Baron, Emilio Cobos Álvarez, Mats Palmgren, Oriol Brufau, Simon Sapin, Xidorn Quan 的投入

变更

本节记录了自上次发布以来的变更。

自 2020 年 7 月 9 日工作草案 (WD) 以来的变更

自 2019 年 8 月 17 日工作草案 (WD) 以来的变更

自 2019 年 4 月 25 日工作草案 (WD) 以来的变更

自 2014 年 3 月 20 日工作草案 (WD) 以来的变更

与 CSS Level 2 的变更

如引言部分所述,与 CSS2.1 相比,此模块有显著变化。

  1. 引入了 ::marker 伪元素,以允许直接对列表标记进行样式设置。
  2. list-style-type 现在接受 <string> 以及来自 [css-counter-styles-3] 的扩展 <counter-style> 值。
  3. 引入了 list-item 预定义计数器标识符。
  4. 添加了 counter-set 属性。
  5. 允许 行内级 (inline-level) 列表项,如 [CSS-DISPLAY-3] 中所引入。

一致性

文档惯例

一致性要求通过描述性断言和 RFC 2119 术语相结合来表达。本文档规范性部分中的关键词“MUST”(必须)、“MUST NOT”(不得)、“REQUIRED”(必需)、“SHALL”(应)、“SHALL NOT”(不应)、“SHOULD”(推荐)、“SHOULD NOT”(不推荐)、“RECOMMENDED”(建议)、“MAY”(可以)和“OPTIONAL”(可选)应按照 RFC 2119 中的描述进行解释。然而,为了可读性,这些词在本文档中不以全大写形式出现。

本规范的所有文本均为规范性文本,明确标记为非规范性、示例和注释的章节除外。[RFC2119]

本规范中的示例均以“例如”一词引入,或者通过 class="example" 与规范性文本隔开,如下所示

这是一个说明性示例。

说明性注释以“Note”一词开头,并使用 class="note" 与规范性文本隔开,如下所示

注意,这是一个说明性注释。

建议(Advisements)是规范性章节,旨在引起特别注意,并使用 <strong class="advisement"> 与其他规范性文本区分开来,如下所示: 用户代理必须提供可访问的替代方案。

符合性类别

本规范为三类一致性定义了一致性要求。

样式表
一份 CSS 样式表
渲染器
一种 用户代理 (UA),它解释样式表的语义并渲染使用它们的文档。
创作工具
一种 用户代理 (UA),用于编写样式表。

如果样式表包含的所有使用本模块定义语法的语句,根据通用 CSS 语法及本模块定义的各功能语法均有效,则该样式表符合本规范。

如果渲染器除了按相应规范解释样式表外,还通过正确解析本规范定义的所有功能并相应地渲染文档来支持这些功能,则该渲染器符合本规范。然而,由于设备限制导致 UA 无法正确渲染文档,并不意味着该 UA 不符合规范。(例如,UA 无需在单色显示器上渲染颜色。)

如果创作工具编写的样式表根据通用 CSS 语法及本模块中各功能的语法是句法正确的,并符合本模块中描述的所有其他样式表一致性要求,则该创作工具符合本规范。

部分实现

为了使作者能够利用前向兼容的解析规则来指定后备值,CSS 渲染器 **必须** 将其无法使用支持级别的任何 @规则、属性、属性值、关键字和其他语法结构视为无效(并 适当忽略)。特别地,用户代理 **不得** 在单一多值属性声明中选择性地忽略不支持的组件值而保留支持的值:如果任何值被视为无效(因为不支持的值必须如此),CSS 要求忽略整个声明。

不稳定及私有功能的实现

为了避免与未来稳定的 CSS 功能发生冲突,CSS 工作组建议在实施不稳定功能和私有扩展遵循最佳实践

非实验性实现

一旦规范达到候选推荐阶段,非实验性实现即可成为可能,实现者应发布他们能够证明根据规范正确实现的任何 CR 级别特性的无前缀实现。

为建立并保持 CSS 在不同实现间的互操作性,CSS 工作组请求非实验性的 CSS 渲染器在发布任何 CSS 功能的无前缀实现之前,向 W3C 提交一份实现报告(并在必要时提交用于该实现报告的测试用例)。提交给 W3C 的测试用例需经 CSS 工作组审阅和修正。

有关提交测试用例和实现报告的详细信息,请访问 CSS 工作组网站 https://w3org.cn/Style/CSS/Test/。问题可发送至 public-css-testsuite@w3.org 邮件列表。

索引

本规范定义的术语

通过引用定义的术语

引用

规范性引用

[CSS-CASCADE-4]
Elika Etemad; Tab Atkins Jr.. CSS 层叠与继承 Level 4. 2020 年 8 月 18 日. 工作草案. URL: https://w3org.cn/TR/css-cascade-4/
[CSS-CONTENT-3]
Elika Etemad; Dave Cramer. CSS 生成内容模块 Level 3. 2019 年 8 月 2 日. 工作草案. URL: https://w3org.cn/TR/css-content-3/
[CSS-COUNTER-STYLES-3]
Tab Atkins Jr.. CSS 计数器样式 3 级。2017年12月14日。CR。URL:https://w3org.cn/TR/css-counter-styles-3/
[CSS-DISPLAY-3]
Tab Atkins Jr.; Elika Etemad. CSS Display Module Level 3. 2020年5月19日. CR. URL: https://w3org.cn/TR/css-display-3/
[CSS-FLEXBOX-1]
Tab Atkins Jr.; 等. CSS 弹性盒布局模块第 1 级. 2018 年 11 月 19 日. 候选推荐标准 (CR). URL: https://w3org.cn/TR/css-flexbox-1/
[CSS-IMAGES-3]
Tab Atkins Jr.; Elika Etemad; Lea Verou. CSS 图像模块第 3 级. 2019 年 10 月 10 日. CR (候选推荐标准). URL: https://w3org.cn/TR/css-images-3/
[CSS-IMAGES-4]
Tab Atkins Jr.; Elika Etemad; Lea Verou. CSS 图像值与替换内容模块 4 级。2017年4月13日。WD。URL:https://w3org.cn/TR/css-images-4/
[CSS-OVERFLOW-3]
David Baron; Elika Etemad; Florian Rivoal. CSS 溢出模块 3 级. 2020 年 6 月 3 日. WD. URL: https://w3org.cn/TR/css-overflow-3/
[CSS-POSITION-3]
Elika Etemad; et al. CSS Positioned Layout Module Level 3. 2020年5月19日. WD. URL: https://w3org.cn/TR/css-position-3/
[CSS-PSEUDO-4]
Daniel Glazman; Elika Etemad; Alan Stearns. CSS 伪元素模块 Level 4. 2019 年 2 月 25 日. 工作草案. URL: https://w3org.cn/TR/css-pseudo-4/
[CSS-SYNTAX-3]
Tab Atkins Jr.; Simon Sapin. CSS 语法模块第 3 级. 2019年7月16日. CR. URL: https://w3org.cn/TR/css-syntax-3/
[CSS-TEXT-3]
Elika Etemad; Koji Ishii; Florian Rivoal. CSS 文本模块 Level 3. 2020 年 4 月 29 日. 工作草案. URL: https://w3org.cn/TR/css-text-3/
[CSS-TEXT-4]
Elika Etemad; 等. CSS 文本模块 Level 4. 2019 年 11 月 13 日. 工作草案. URL: https://w3org.cn/TR/css-text-4/
[CSS-VALUES-3]
Tab Atkins Jr.; Elika Etemad. CSS 值与单位模块第 3 级. 2019年6月6日. CR. URL: https://w3org.cn/TR/css-values-3/
[CSS-VALUES-4]
Tab Atkins Jr.; Elika Etemad. CSS 值与单位模块 第4级. 2019年1月31日. WD. URL: https://w3org.cn/TR/css-values-4/
[CSS-VARIABLES-1]
Tab Atkins Jr.. CSS Custom Properties for Cascading Variables Module Level 1. 3 December 2015. CR. URL: https://w3org.cn/TR/css-variables-1/
[CSS-WRITING-MODES-3]
Elika Etemad; Koji Ishii. CSS 书写模式 3 级。2019年12月10日。REC。URL:https://w3org.cn/TR/css-writing-modes-3/
[CSS-WRITING-MODES-4]
Elika Etemad; Koji Ishii. CSS 书写模式第 4 级. 2019年7月30日. CR. URL: https://w3org.cn/TR/css-writing-modes-4/
[CSS2]
Bert Bos; et al. 层叠样式表第 2 级修订版 1 (CSS 2.1) 规范. 2011年6月7日. REC. URL: https://w3org.cn/TR/CSS21/
[DOM]
Anne van Kesteren. DOM 标准。现行标准。网址:https://dom.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML 标准。现行标准。网址:https://html.whatwg.cn/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 标准。现行标准。网址:https://infra.spec.whatwg.org/
[RFC2119]
S. Bradner. RFC 中用于指示需求级别的关键词. 1997 年 3 月. 最佳当前实践. URL: https://tools.ietf.org/html/rfc2119
[SELECTORS-4]
Elika Etemad; Tab Atkins Jr.. 选择器 4 级. 2018年11月21日. WD. URL: https://w3org.cn/TR/selectors-4/
[SVG2]
Amelia Bellamy-Royds; 等人. 可缩放矢量图形 (SVG) 2. 2018年10月4日. CR. URL: https://w3org.cn/TR/SVG2/

参考资料

[CSS-ANIMATIONS-1]
Dean Jackson; 等人. CSS 动画 1 级. 2018年10月11日. WD. URL: https://w3org.cn/TR/css-animations-1/
[CSS-COLOR-3]
Tantek Çelik; Chris Lilley; David Baron. CSS 颜色模块 3 级. 2018年6月19日. REC. URL: https://w3org.cn/TR/css-color-3/
[CSS-COLOR-4]
Tab Atkins Jr.; Chris Lilley. CSS 颜色模块 Level 4. 2019 年 11 月 5 日. 工作草案. URL: https://w3org.cn/TR/css-color-4/
[CSS-FONTS-3]
John Daggett; Myles Maxfield; Chris Lilley. CSS 字体模块 3 级. 2018年9月20日. REC. URL: https://w3org.cn/TR/css-fonts-3/
[CSS-TRANSITIONS-1]
David Baron; et al. CSS Transitions. 2018 年 10 月 11 日. 工作草案. URL: https://w3org.cn/TR/css-transitions-1/

属性索引

名称初始值应用于继承百分比动画类型 (Animation type)规范顺序计算值
counter-increment [ <counter-name> <integer>? ]+ | nonenone(无)所有元素不可用按计算值类型按语法关键字 none 或列表,列表中的每一项都是一个与整数配对的标识符
counter-reset [ <counter-name> <integer>? ]+ | nonenone(无)所有元素不可用按计算值类型按语法关键字 none 或列表,列表中的每一项都是一个与整数配对的标识符
counter-set [ <counter-name> <integer>? ]+ | nonenone(无)所有元素不可用按计算值类型按语法关键字 none 或列表,列表中的每一项都是一个与整数配对的标识符
list-style <'list-style-position'> || <'list-style-image'> || <'list-style-type'>见各个属性列表项见各个属性见各个属性见各个属性按语法见各个属性
list-style-image <image> | nonenone(无)列表项不可用离散 (discrete)按语法关键字 none 或计算后的 <image>
list-style-position inside | outsideoutside (外侧)列表项不可用离散 (discrete)按语法关键字,但请参阅正文
list-style-type <counter-style> | <string> | nonedisc列表项不可用离散 (discrete)按语法指定的值
marker-side match-self | match-parentmatch-self列表项不可用离散 (discrete)按语法指定关键字

问题索引

white-space: pre 没有完全正确的行为;text-space-collapse: preserve-spaces + text-space-trim: discard-after 可能更接近此处所需的功能。参见 问题 4448问题 4891 中的讨论。
这是来自 CSS2 的模糊不清的废话,需要真正的定义。
或者,outside 可以将标记布局为主要行内框的前一个兄弟节点。
为了使该顺序正确地对标记内的标点符号进行定位,它还需要采用父元素的 direction 值。<https://github.com/w3c/csswg-drafts/issues/4202>
关于 重命名关键字 以及 list-style-position 合并 有开放的问题。
计数器有时不仅对于打印标记有用。总的来说,它们提供了按顺序编号元素的能力,这对于其他属性的引用非常有用。例如,使用 order 将一个元素放在其他两个特定元素之间,目前要求您在所需插入点之前和/或之后的所有元素上显式设置 order。不过,如果您可以将所有内容的 order 值设置为计数器,那么您可以更轻松地将元素插入到其他两个元素之间的任意位置。

其他用例涉及带有相互之间略有不同的变换(transforms)的嵌套或兄弟元素。目前,您必须使用预处理器以合理的方式执行此操作,但计数器将使其在“普通”CSS 中良好运行。

(您目前可以通过使用 自定义属性 和堆叠嵌套的 calc() 来构建嵌套情况下的连续值,但这稍微有点笨拙,并且不适用于兄弟元素。)

建议添加一个 counter-value(<counter-name>) 函数,它返回命名计数器的值作为整数,而不是返回字符串。

参见 问题 1026

关于如何在 CSS 中支持 ol[reversed] 列表编号的讨论正在进行中。参见,例如 问题 4181