CSS 列表和计数器模块 第3版

W3C 工作草案,

此版本:
https://www.w3.org/TR/2020/WD-css-lists-3-20201117/
最新发布版本:
https://www.w3.org/TR/css-lists-3/
编辑草案:
https://drafts.csswg.org/css-lists-3/
先前版本:
问题跟踪:
CSSWG 问题库
在文档中
编辑:
Elika J. Etemad / fantasai (特邀专家)
Tab Atkins (谷歌)
前任编辑:
(谷歌)
(曾任微软)
建议编辑此规范:
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发布的文档和最新的技术报告修订列表可以在W3C技术报告索引找到。

本文件由CSS工作组发布为工作草案。作为工作草案的发布并不意味着W3C会员的认可。

这是一个草稿文件,可能会随时更新、替换或被其他文档取代。引用本文件时不应当将其视为工作进展。

请通过在GitHub上提交问题(首选)发送反馈,标题中包括规范代码“css-lists”,例如:“[css-lists] …评论摘要…”。所有问题和评论都会被归档。或者,可以将反馈发送至(归档)的公共邮件列表www-style@w3.org

本文件受2020年9月15日W3C过程文件的约束。

本文件由一个遵循W3C专利政策的团体生成。W3C维护一个公共专利披露列表,列出了与该小组的交付物相关的任何专利披露;该页面还包括专利披露的说明。任何实际了解其认为包含核心权利要求的专利的人,必须按照W3C专利政策第6节的规定披露该信息。

1. 引言

本规范定义了 ::marker 伪元素, 生成标记的 列表项 显示类型, 以及几个控制标记位置和样式的属性。

它还定义了 计数器, 计数器是特殊的数字对象, 通常用于生成标记的默认内容。

例如,以下示例演示了如何使用标记为每个编号列表项添加括号:
<style>
li::marker { content: "(" counter(list-item, lower-roman) ")";
}
li { display: list-item; }
</style>
<ol>
  <li>这是第一项。
  <li>这是第二项。
  <li>这是第三项。
</ol>

这将产生类似于以下内容:

  (i) 这是第一项。
 (ii) 这是第二项。
(iii) 这是第三项。

注意: 请注意,这个示例的内容比在HTML中通常需要的内容要冗长得多, 因为用户代理的默认样式表处理了大部分必要的样式。

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

1.1. 值定义

本规范遵循 CSS属性定义约定, 来自 [CSS2], 使用 值定义语法, 来源于 [CSS-VALUES-3]。 本规范未定义的值类型在 CSS 值与单位[CSS-VALUES-3]中定义。 与其他CSS模块结合可能会扩展这些值类型的定义。

除了在其定义中列出的属性特定值之外, 本规范定义的所有属性 也接受 CSS广域关键字 作为它们的属性值。 为了可读性,它们没有被显式重复。

2. 声明列表项

列表项是任何其 display 属性设置为 list-item 的元素。 列表项 生成 ::marker 伪元素;没有其他元素这样做。 此外,列表项 自动递增一个隐含的 list-item 计数器(见 § 4.6 隐式列表项计数器)。

3. 标记

列表项 显示类型的定义特征是其 标记, 是帮助标示每个 列表项 在列表中开始的符号或序数。 在CSS布局模型中,列表项 标记由与每个 列表项 关联的 标记盒 表示。 此 标记 的内容可以通过在 列表项 上设置 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: "备注 " counter(
    note-counter)
    ":"; 
}
</style> 
<p>
    这是本文档的第一段。
<p class="note">
    这是一篇非常简短的文档。
<p>
    这是结束。

它应该呈现为如下内容:

        这是第一段
        在这个文档中。

备注 1: 这是一个非常简短的
        文档。

        这是结束。
通过使用 ::marker 伪元素,列表的标记可以 独立于列表项文本进行样式设置:
<style>
p {
    margin-left: 8em }
    /* 为计数器留出空间 */
li {
    list-style-type: lower-roman;
}
li::
    marker {
    color: blue;
    font-weight:bold;
    }
</style>
<p>
    这是一个较长的前导段落 ...
<ol>
  <li>
    这是第一项。
  <li>
    这是第二项。
  <li>
    这是第三项。
</ol>
<p>
    这是一个较长的后续段落 ...

前面的文档应该呈现如下:

       这是一个较长的
       前导段落 ...

  i.   这是第一项。
 ii.   这是第二项。
iii.   这是第三项。

       这是一个较长的
       后续段落 ...

之前唯一的标记样式方法是通过继承;需要将所需的标记样式放在列表项上,然后在列表项实际内容周围的包装元素上还原该样式。

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

3.1.1. 适用于 ::marker 的属性

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

预计未来的规范将扩展此属性列表;然而,目前标记盒布局尚未完全定义, 因此仅允许这些属性。

标记盒中,其他属性在作者源级联中不得 产生效果。用户代理可以将这些属性视为不适用,或者通过设置用户代理源 !important规则来强制其值。 然而,适用于文本的可继承属性可以设置在::marker伪元素上:这些属性将继承并对其文本内容生效。

适用于文本的属性示例,因此在::marker上声明时将应用于::marker的内容:

用户代理必须将以下规则添加到其默认样式表:

::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 可能更接近所需的行为。 请参见问题 4448问题 4891中的讨论。

3.2. 生成标记内容

标记盒marker box的内容由第一个真实的条件决定:

content::marker 本身不为normal
标记盒的内容由marker boxcontent属性定义,完全与::before相同。
list-style-image源元素上定义了一个标记图像
标记盒包含一个匿名 行内 替换元素,表示指定的标记图像,后面跟着一个由单个空格(U+0020 SPACE)组成的文本序列
list-style-type源元素上定义了一个标记字符串
标记盒包含一个由指定的标记字符串组成的文本序列
否则
标记盒没有内容,并且::marker不会生成一个盒子。

此外,用户代理可以将任何保留的强制换行转换为空格或丢弃。

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

名称: list-style-image
值: <image> | none
初始值: none
适用对象: 列表项
继承:
百分比: 不适用
计算值: 关键字none或计算的<image>
标准顺序: 按语法
动画类型: 离散

指定了标记图像, 该图像用于填充列表项的 标记,当其内容正常时。 可用值如下:

<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
适用对象: 列表项
继承:
百分比: 不适用
计算值: 指定值
标准顺序: 按语法
动画类型: 离散

指定了标记字符串, 该字符串用于填充列表项标记,当其内容值为正常且没有标记图像时。 可用值如下:

<counter-style>
指定元素的标记字符串为 作为指定列表项计数器的值,使用指定的<counter-style>

具体来说, 标记字符串生成计数器表示列表项计数器值的结果, 使用指定的<counter-style>, 以指定的前缀开头, 并以指定的<counter-style>后缀结尾。 如果指定的<counter-style> 不存在,则假定为十进制

<string>
元素的标记字符串是指定的<string>
none
元素没有标记字符串
以下示例演示了如何将标记设置为各种值:
ul { list-style-type: "★"; }
    /* 将标记设置为“星号”字符 */

p.note { 
  display: list-item; 
  list-style-type: "Note: "; 
  list-style-position: inside; 
} 
/* 为注释段落赋予标记,由字符串“Note: ”组成 */

ol { list-style-type: upper-roman; } 
/* 将所有有序列表设置为使用上罗马计数样式 */ 
   (在计数样式规范中定义 [[CSS-COUNTER-STYLES]]) */

ul { list-style-type: symbols(cyclic '○' '●'); } 
/* 设置所有无序列表项交替使用空心和实心圆作为标记。 */

ul { list-style-type: none; } 
/* 完全抑制标记,除非指定有效图像的list-style-image。 */ 

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

名称: list-style-position
值: inside | outside
初始值: outside
适用对象: 列表项
继承:
百分比: 不适用
计算值: 关键字,但见正文
标准顺序: 按语法
动画类型: 离散

此属性决定::marker是以内联方式呈现, 还是定位在列表项的外部。 值如下:

inside
没有特殊效果。 (标记在::marker 是列表项内容的一个内联元素。)
outside
如果列表项块容器: 则标记框是一个块容器,并位于主块框的外部; 然而,列表项标记相对于浮动元素的位置未定义。 CSS并未指定标记框的精确位置 或其在绘制顺序中的位置, 但要求将其放置在行起始的一侧, 使用由marker-side指示的框的书写模式。 标记框相对于主块框的边框是固定的, 并且不会随主框的内容滚动。 如果元素的溢出属性设置为其他值而非可见,则用户代理可能会隐藏标记。 (此允许在未来可能会改变。) 标记框的大小或内容可能会影响 主块框的高度 和/或其首行框的高度, 并在某些情况下可能导致新行框的创建; 此交互关系也未定义。

这是CSS2中的含糊定义,需要一个真实的定义。

如果列表项内联框: 该值等同于inside

另外,outside可以将标记布局为主内联框的前一个兄弟。

例如:
<style>
  ul.compact { list-style: inside; }
  ul         { list-style: outside; }
</style>
<ul class=compact>
  <li>第一个“inside”列表项</li>
  <li>第二个“inside”列表项</li>
</ul>
<hr>
<ul>
  <li>第一个“outside”列表项</li>
  <li>第二个“outside”列表项</li>
</ul>

上述示例可能会格式化为:

  * 第一个 "inside" 列表
  项位于最前
  * 第二个 "inside" 列表
  项位于第二

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

* 第一个 "outside" 列表
  项位于最前
* 第二个 "outside" 列表
  项位于第二

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 }  /* 任何 UL */
ul ul { list-style: circle outside } /* 任何 UL 的子 UL */

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

list-style: none disc;
/* 将图像设置为 "none",类型设置为 "disc"。 */

list-style: none url(bullet.png);
/* 将图像设置为 "url(bullet.png)",类型设置为 "none"。 */

list-style: none;
/* 将图像和类型都设置为 "none"。 */

list-style: none disc url(bullet.png);
/* 语法错误 */

注意: <counter-style> 的值可以在list-style-type中创建语法歧义。 由于这些值最终是<custom-ident>值, 所以在[CSS-VALUES-3]中的解析规则适用。

尽管作者可以直接在列表项元素上指定list-style信息 (例如,HTML中的li), 他们应该谨慎行事。 考虑以下规则:
ol.alpha li { list-style: lower-alpha; }
ul li       { list-style: disc; }

上述示例不会按预期工作。 如果将一个ul 嵌套在一个ol class=alpha中, 第一个规则的特定性会使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
适用对象: 列表项
继承:
百分比: 不适用
计算值: 指定的关键字
标准顺序: 按语法
动画类型: 离散

marker-side 属性指定了是否一个外部标记框的位置是基于列表项本身的方向性(即它的原始元素)还是列表容器的方向性(即原始元素的父元素)。在第一种情况下,标记的位置可以在同一列表的项目之间变化,基于每个列表项单独分配的方向性;在第二种情况下,所有标记将对齐在同一侧,由整体列表分配的方向性决定。

match-self
标记框 是使用::marker原始元素的方向性来定位的。
match-parent
标记框 是使用::marker原始元素的父元素的方向性来定位的。
默认情况下,元素或::marker伪元素根据其列表项的方向性自行定位。然而,如果列表项与多个可能具有不同方向性的其他列表项分组在一起(例如,在HTML中的多个具有不同"dir"属性的<li>),有时将所有标记排列在同一侧会更有用,因此作者可以在那一侧指定一个单一的“边距”,确保所有标记都位于该边距内并且可见。

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

<ul>
  <li>英语一
  <li dir=rtl>阿拉伯语
  <li>英语三
  <li dir=rtl>阿拉伯语三
</ul>
match-self match-parent
* 英语一
     阿拉伯语 *
* 英语三
    阿拉伯语三 *
* 英语一
*    阿拉伯语
* 英语三
*   阿拉伯语三

为了使标点符号在标记内正确排序, 还需要考虑父元素的方向值。 <https://github.com/w3c/csswg-drafts/issues/4202>

有关重命名关键字list-style-position 合并 的问题仍在开放中。

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

计数器 是一个特殊的数字跟踪器,用于自动编号 CSS 中的列表项等多种用途。每个元素都有一个零或多个计数器的集合,这些计数器以类似于继承属性值的方式通过文档树继承。计数器 具有一个 名称创建者,用于识别计数器,并且有一个整数 。它们通过 计数器属性 counter-incrementcounter-setcounter-reset 创建和操作,并与 counter()counters() 函数表示法一起使用。

计数器在 CSS 语法中通过 <counter-name> 类型引用,表示其名称为 <custom-ident><counter-name> 名称不能与关键字 none 匹配;这样的标识符被认为是无效的 <counter-name>

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

  1. 现有计数器从前面的元素继承

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

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

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

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

用户代理可能对计数器的最大值或最小值有实现特定的限制。如果计数器重置、设置或递增将使值超出该范围,则必须将值限制在该范围内。

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,然后设置或递增其值。

此示例演示了如何对章节和部分进行编号,格式为 "第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() 函数则使用包含该元素的所有给定名称的计数器。

因此,作用域 的计数器从文档中第一个实例化该计数器的元素开始,并包括该元素的后代和后继兄弟元素及其后代。然而,它不包括任何在后续兄弟元素上通过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的子元素都将引用该计数器。

如果我们用nth 实例表示item计数器为 itemn,则以下 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. 创建和继承计数器

文档中的每个元素或伪元素都有一组(可能为空)的计数器,这些计数器在该元素的作用域内,或者通过从另一个元素继承,或者通过在元素上直接实例化。这些计数器表示为一个集合,每个值是一个元组,包括: 字符串(表示计数器的名称), 一个元素(表示计数器的创建者), 和一个整数(表示计数器的)。 该集合中给定名称的最新计数器表示该名称的最内层计数器。

4.4.1. 继承计数器

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

  2. element counters表示element自身的CSS计数器集合, 复制element的父元素的CSS计数器集合

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

    对于每个 countersibling counters, 如果element counters中尚不存在同名计数器, 将counter的副本附加到element counters

  4. value sourceCSS计数器集合,该集合为element树顺序中紧接着element的元素。

    对于每个 source countervalue source, 如果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#foo元素作为ul的第一个子元素,继承了此计数器。它的父元素也是其在树顺序中紧接着的元素,因此它继承了值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上实例化一个给定name的计数器,并设置其初始value
  1. counterselementCSS计数器集合

  2. innermost countercounters 中最后一个名为 name计数器。 如果 innermost counter 的源元素是 element 或者 element 的前一个兄弟元素, 则 移除 innermost countercounters 中。

  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计数器递增1,因此具有数字list-style-type的连续列表项将按默认顺序连续编号——即使作者将counter-increment设置为其他值,如counter-increment: itemnumber或甚至none。这保护了自动list-item计数器不被意外覆盖。

但是,由于自动list-item递增在列表项counter-increment明确提及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. 第一个项目
4. 第二个项目
6. 第三个项目

用户代理和主机语言应确保list-item计数器值默认反映主机语言语义规定的底层数值,在其用户代理样式表和表现提示样式映射中设置列表项样式。参见,例如附录 A: HTML 的示例样式表

在以下示例中,content属性用于创建分层编号,钩入list-item计数器,因此尊重通过 HTML 施加的任何编号更改:
ol > li::marker { content: counters(list-item,'.') '.'; }

使用此规则的嵌套列表将呈现为

1. 第一个顶级项目
5. 第二个顶级项目,值=5
   5.3. 第一个第二级项目,列表开始=3
   5.4. 第二个第二级项目,列表开始=3
        5.4.4. 第一个第三层级项目,倒序列表
        5.4.3. 第二个第三层级项目,倒序列表
        5.4.2. 第三个第三层级项目,倒序列表
        5.4.1. 第四个第三层级项目,倒序列表
   5.5. 第三个第二级项目,列表开始=3
6. 第三个顶级项目

给定标记如

<ol>
  <li>第一个顶级项目
  <li value=5>第二个顶级项目,值=5
    <ol start=3>
      <li>第一个第二级项目,列表开始=3
      <li>第二个第二级项目,列表开始=3
        <ol reversed>
          <li>第一个第三层级项目,倒序列表
          <li>第二个第三层级项目,倒序列表
          <li>第三个第三层级项目,倒序列表
          <li>第四个第三层级项目,倒序列表
        </ol>
    </ol>
  <li>第三个第二级项目,列表开始=3
  <li>第三个顶级项目
</ol>

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

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

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

其中<counter-style>指定用于生成命名计数器的表示形式的计数器样式,正如生成计数器中定义的那样。

counter()
表示元素的最内层计数器的值,该计数器在元素的CSS计数器集中使用<counter-name>指定的计数器样式,并且样式名为<counter-style>
counters()
表示元素的计数器在元素的CSS计数器集中命名的所有计数器的值,使用名为<counter-name>的计数器样式,并且样式名为计数器样式,按外层优先至内层最后的顺序排列,并通过指定的<string>连接。

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

如果在使用counter()counters()的元素上不存在命名为<counter-name>的计数器,则将首先以初始值为0对其进行实例化

H1::before        { content: counter(chno, upper-latin) ". " }
/* 生成标题如 "A. A History of Discontent" */

H2::before        { content: counter(section, upper-roman) " - " }
/* 生成标题如 "II - The Discontent Part" */

BLOCKQUOTE::after { content: " [" counter(bq, decimal) "]" }
/* 生成以 "... [3]" 结尾的块引用 */

DIV.note::before  { content: counter(notecntr, disc) " " }
/* 在每个div.note之前简单生成一个项目符号 */

P::before         { content: counter(p, none) }
/* 插入无内容 */
以下示例展示了counters()函数的简单用法:
<ul>
  <li>一个</li>
  <li>两个
    <ul>
      <li>嵌套一个</li>
      <li>嵌套两个</li>
    </ul>
  </li>
  <li>三个</li>
</ul>
<style>
li::marker { content: '(' counters(list-item,'.') ') '; }
</style>

上述文档应渲染如下:

(1) 一个
(2) 两个
   (2.1) 嵌套一个
   (2.2) 嵌套两个
(3) 三个
由于计数器会遗传给兄弟元素,因此它们可以用来编号标题和子标题,而不需要相互嵌套。不幸的是,这会妨碍使用counters(),因为兄弟元素的计数器不嵌套,但可以创建多个计数器并手动连接它们:
<h1>第一个H1</h1>
...
<h2>第一个H2在H1中</h2>
...
<h2>第二个H2在H1中</h2>
...
<h3>第一个H3在H2中</h3>
...
<h1>第二个H1</h1>
...
<h2>第一个H2在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. 第一个H1
...
A.1 第一个H2在H1中
...
A.2 第二个H2在H1中
...
A.2.i 第一个H3在H2中
...
B. 第二个H1
...
B.1 第一个H2在H1中
...
计数器有时在打印标记以外的地方非常有用。一般来说,它们提供了按顺序编号元素的能力,这对其他属性的引用很有帮助。例如,使用order将元素放在两个特定元素之间,当前需要您在所有要素之前和/或之后明确放置order。然而,如果您可以将所有元素的order值设置为一个计数器,那么您就可以更容易地将元素插入到其他元素之间的任意位置。

其他用例涉及具有不同变换的嵌套或兄弟元素。今天,您需要使用预处理器以合理的方式做到这一点,但计数器可以使其在“纯”CSS中很好地工作。

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

请参阅问题1026

附录 A:HTML 的示例样式表

本节为信息性,而非规范性。[HTML] 渲染章节定义了适用于 HTML 列表的规范默认属性;此示例样式表旨在通过熟悉的标记约定来说明 CSS 特性。

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

/* 设置列表项 */
li {
  display: list-item; /* 隐含 'counter-increment: list-item' */
}

/* 设置 ol 和 ul,使其作用于 list-item 计数器 */
ol, ul {
  counter-reset: list-item;
}

/* 列表的默认样式类型 */
ol { list-style-type: decimal; }
ul { list-style-type: toggle(disc, circle, square); }

/* ol 和 ul 元素上的 type 属性 */
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; }

/* ol 元素上的 start 属性 */
ol[start] {
  counter-reset: list-item calc(attr(start integer, 1) - 1);
}

/* li 元素上的 value 属性 */
li[value] {
  counter-set: list-item attr(value integer, 1);
}

/* 盒模型规则 */
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> 以及扩展的 <counter-style> 值,来自 [css-counter-styles-3]
  3. 引入了 list-item 预定义计数器标识符。
  4. 新增了 counter-set 属性。
  5. 允许使用 inline-level 列表项,如在 [CSS-DISPLAY-3] 中引入的。

合规性

文档约定

合规性要求通过描述性断言和 RFC 2119 术语的组合来表达。关键字“必须”、“必须不”、“要求”、“应”、“不应”、“应该”、“推荐”、“可以”和“可选”在本文件的规范部分应按照 RFC 2119 中的描述进行解释。然而,为了可读性,这些词在本规范中并不都是大写字母。

本规范的所有文本都是规范性的,除了明确标记为非规范性的部分、示例和注释。[RFC2119]

本规范中的示例用“例如”引入,或通过 class="example" 与规范文本分开,如下所示:

这是一个信息性示例。

信息性注释以“注意”开头,并通过 class="note" 与规范文本分开,如下所示:

注意,这是一条信息性注释。

建议是规范性部分,样式上以特殊的方式引起注意,并通过 <strong class="advisement"> 与其他规范文本分开,如下所示: 用户代理必须提供可访问的替代方案。

合规性类别

对本规范的合规性定义有三个合规性类别:

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

如果样式表中使用本模块定义的语法的所有语句在通用 CSS 语法和本模块定义的每个特性的各自语法中都是有效的,那么该样式表就是符合本规范的。

如果渲染器除了根据适当规范解释样式表外,还支持本规范定义的所有特性,通过正确解析这些特性并相应地渲染文档,那么该渲染器就是符合本规范的。然而,用户代理由于设备限制而无法正确渲染文档并不会使用户代理不符合规范。(例如,用户代理不必在单色显示器上渲染颜色。)

如果创作工具编写的样式表根据通用 CSS 语法和本模块中每个特性的各自语法是语法上正确的,并符合本模块中描述的样式表的所有其他合规性要求,则该创作工具就是符合本规范的。

部分实现

为了让作者利用向前兼容的解析规则来分配后备值,CSS 渲染器必须将任何没有可用支持级别的规则、属性、属性值、关键字和其他语法结构视为无效(并适当忽略)。特别是,用户代理必须不选择性地忽略不支持的组件值,并在单个多值属性声明中尊重支持的值:如果任何值被视为无效(因为不支持的值必须如此),CSS 要求整个声明被忽略。

不稳定和专有特性的实现

为了避免与未来稳定的 CSS 特性发生冲突,CSS 工作组建议遵循最佳实践,以实现不稳定特性和专有扩展

非实验性实现

一旦规范达到候选推荐阶段,非实验性实现是可能的,实施者应发布任何能够证明根据规范正确实现的 CR 级特性的未加前缀实现。

为了建立和维护 CSS 在不同实现中的互操作性,CSS 工作组请求非实验性 CSS 渲染器在发布任何 CSS 特性的未加前缀实现之前,向 W3C 提交实施报告(如有必要,提交用于该实施报告的测试用例)。提交给 W3C 的测试用例将由 CSS 工作组进行审查和更正。

有关提交测试用例和实施报告的更多信息,请访问 CSS 工作组的网站 https://www.w3.org/Style/CSS/Test/。如有问题,请向 public-css-testsuite@w3.org 邮件列表咨询。

索引

本规范定义的术语

通过引用定义的术语

参考文献

规范性参考文献

[CSS-CASCADE-4]
Elika Etemad; Tab Atkins Jr.. CSS 级联与继承 第4版. 2020年8月18日. WD. URL: https://www.w3.org/TR/css-cascade-4/
[CSS-CONTENT-3]
Elika Etemad; Dave Cramer. CSS 生成内容模块 第3版. 2019年8月2日. WD. URL: https://www.w3.org/TR/css-content-3/
[CSS-COUNTER-STYLES-3]
Tab Atkins Jr.. CSS 计数器样式 第3版. 2017年12月14日. CR. URL: https://www.w3.org/TR/css-counter-styles-3/
[CSS-DISPLAY-3]
Tab Atkins Jr.; Elika Etemad. CSS 显示模块 第3版. 2020年5月19日. CR. URL: https://www.w3.org/TR/css-display-3/
[CSS-FLEXBOX-1]
Tab Atkins Jr.; et al. CSS 弹性盒布局模块 第1版. 2018年11月19日. CR. URL: https://www.w3.org/TR/css-flexbox-1/
[CSS-IMAGES-3]
Tab Atkins Jr.; Elika Etemad; Lea Verou. CSS 图像模块 第3版. 2019年10月10日. CR. URL: https://www.w3.org/TR/css-images-3/
[CSS-IMAGES-4]
Tab Atkins Jr.; Elika Etemad; Lea Verou. CSS 图像值与替换内容模块 第4版. 2017年4月13日. WD. URL: https://www.w3.org/TR/css-images-4/
[CSS-OVERFLOW-3]
David Baron; Elika Etemad; Florian Rivoal. CSS 溢出模块 第3版. 2020年6月3日. WD. URL: https://www.w3.org/TR/css-overflow-3/
[CSS-POSITION-3]
Elika Etemad; et al. CSS 定位布局模块 第3版. 2020年5月19日. WD. URL: https://www.w3.org/TR/css-position-3/
[CSS-PSEUDO-4]
Daniel Glazman; Elika Etemad; Alan Stearns. CSS 伪元素模块 第4版. 2019年2月25日. WD. URL: https://www.w3.org/TR/css-pseudo-4/
[CSS-SYNTAX-3]
Tab Atkins Jr.; Simon Sapin. CSS 语法模块 第3版. 2019年7月16日. CR. URL: https://www.w3.org/TR/css-syntax-3/
[CSS-TEXT-3]
Elika Etemad; Koji Ishii; Florian Rivoal. CSS 文本模块 第3版. 2020年4月29日. WD. URL: https://www.w3.org/TR/css-text-3/
[CSS-TEXT-4]
Elika Etemad; et al. CSS 文本模块 第4版. 2019年11月13日. WD. URL: https://www.w3.org/TR/css-text-4/
[CSS-VALUES-3]
Tab Atkins Jr.; Elika Etemad. CSS 值和单位模块 第3版. 2019年6月6日. CR. URL: https://www.w3.org/TR/css-values-3/
[CSS-VALUES-4]
Tab Atkins Jr.; Elika Etemad. CSS 值和单位模块 第4版. 2019年1月31日. WD. URL: https://www.w3.org/TR/css-values-4/
[CSS-VARIABLES-1]
Tab Atkins Jr.. CSS 自定义属性级联变量模块 第1版. 2015年12月3日. CR. URL: https://www.w3.org/TR/css-variables-1/
[CSS-WRITING-MODES-3]
Elika Etemad; Koji Ishii. CSS 书写模式 第3版. 2019年12月10日. REC. URL: https://www.w3.org/TR/css-writing-modes-3/
[CSS-WRITING-MODES-4]
Elika Etemad; Koji Ishii. CSS 书写模式 第4版. 2019年7月30日. CR. URL: https://www.w3.org/TR/css-writing-modes-4/
[CSS2]
Bert Bos; et al. 层叠样式表 第2版 修订版1 (CSS 2.1) 规范. 2011年6月7日. REC. URL: https://www.w3.org/TR/CSS21/
[DOM]
Anne van Kesteren. DOM 标准. 现行标准. URL: https://dom.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML 标准. 现行标准. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 标准. 现行标准. URL: 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://www.w3.org/TR/selectors-4/
[SVG2]
Amelia Bellamy-Royds; et al. 可扩展矢量图形(SVG) 第2版. 2018年10月4日. CR. URL: https://www.w3.org/TR/SVG2/

非规范性参考文献

[CSS-ANIMATIONS-1]
Dean Jackson; et al. CSS 动画 第1版. 2018年10月11日. WD. URL: https://www.w3.org/TR/css-animations-1/
[CSS-COLOR-3]
Tantek Çelik; Chris Lilley; David Baron. CSS 颜色模块 第3版. 2018年6月19日. REC. URL: https://www.w3.org/TR/css-color-3/
[CSS-COLOR-4]
Tab Atkins Jr.; Chris Lilley. CSS 颜色模块 第4版. 2019年11月5日. WD. URL: https://www.w3.org/TR/css-color-4/
[CSS-FONTS-3]
John Daggett; Myles Maxfield; Chris Lilley. CSS 字体模块 第3版. 2018年9月20日. REC. URL: https://www.w3.org/TR/css-fonts-3/
[CSS-TRANSITIONS-1]
David Baron; et al. CSS 过渡. 2018年10月11日. WD. URL: https://www.w3.org/TR/css-transitions-1/

属性索引

名称 初始值 适用对象 继承 %ages 动画类型 规范顺序 计算值
counter-increment [ <counter-name> <integer>? ]+ | none none 所有元素 不适用 按计算值类型 按语法 关键字 none 或者一个列表,每个项目是一个标识符与一个整数的配对
counter-reset [ <counter-name> <integer>? ]+ | none none 所有元素 不适用 按计算值类型 按语法 关键字 none 或者一个列表,每个项目是一个标识符与一个整数的配对
counter-set [ <counter-name> <integer>? ]+ | none none 所有元素 不适用 按计算值类型 按语法 关键字 none 或者一个列表,每个项目是一个标识符与一个整数的配对
list-style <'list-style-position'> || <'list-style-image'> || <'list-style-type'> 见各个属性 列表项 见各个属性 见各个属性 见各个属性 按语法 见各个属性
list-style-image <image> | none none 列表项 不适用 离散 按语法 关键字 none 或计算出的 <image>
list-style-position inside | outside outside 列表项 不适用 离散 按语法 关键字,但见正文
list-style-type <counter-style> | <string> | none disc 列表项 不适用 离散 按语法 指定值
marker-side match-self | match-parent match-self 列表项 不适用 离散 按语法 指定关键字

问题索引

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 值设置为一个计数器, 您可以更轻松地在两个其他元素之间插入一个元素。

其他用例涉及具有稍微不同变换的嵌套或兄弟元素。 如今,您必须使用预处理器以合理的方式做到这一点, 但计数器可以使其在“普通”CSS中有效。

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

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

请参阅问题 1026

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