CSS第三级选择器 Selectors Level 3 文档翻译

时间:2022-04-17 01:51:26

Selectors Level 3 CSS第三级选择器

文章开始的目录树生成错误,请不要参考。

规范源地址:https://www.w3.org/TR/2011/REC-css3-selectors-20110929/

概要

选择器(selector)是用来在树中匹配元素的模式,是用来选择XML文档中节点的几种技术之一。选择器对HTML和XML进行了优化,被设计用来在注重性能的代码中执行。

CSS是一个被用来描述如何在屏幕等处渲染HTML和XML文档的语言。CSS使用选择器来为文档中的元素绑定样式属性(style properties)。

这篇文档描述了已经在CSS1和CSS2中出现,以及之后将在CSS3中新出现的选择器,在其他语言中也可能用到它们。

选择器通过下面的方式定义:

expression * element -> boolean

也就是说,给定一个元素和一个选择器,表示出这个元素是否匹配该选择器。

此文章的状态

1.介绍

2.选择器

一个选择器表示了一个结构。这个结构可以被用来决定文档树中的哪一个元素与之对应。

选择器可以被用来匹配简单的元素名称也可以用被用来匹配复杂的上下文结构。

下面的表格总结了选择器的语法:
CSS第三级选择器 Selectors Level 3 文档翻译

3.大小写敏感

所有的选择器语法除不在选择器控制下的部分外,在ASCII范围内是大小写不敏感的。选择器中文档语言的元素名称、属性名称和属性值的大小写敏感依赖于文档语言本身。例如,在HTML中元素名称是大小写不敏感的,但在XML中是大小写敏感的。

4.选择器语法

一个选择器由是一个或多个被组合器隔开的 简单选择器序列 组成的链条。一个伪元素可能被添加到最后的简单选择器序列之后。

一个简单选择器序列是由没有被组合器隔开的简单选择器组成的链条。它总是以全局选择器或类型选择器开始。

一个简单选择器可以是类型选择器,全局选择器,属性选择器,类选择器,ID选择器或伪类。

组合器是:空白符,大于号 (U+003E, >), 加号 (U+002B, +) 和 波浪符 (U+007E, ~)。空白符可能出现在组合器和简单选择器之间。只有空格 (U+0020), tab (U+0009), 换行符 (U+000A), 回车符 (U+000D), 和 换页符 (U+000C)可以出现在空白符中。任何其他的类似空格的字符,例如”em-space” (U+2003) 和 “ideographic space” (U+3000)不属于空白符。

在文档中被选择器表示的元素被称为选择器的受体(subject)。若一个选择器由一个单一的简单选择器序列组成,这个选择器表示的内容为此序列所表示的内容。往序列前插入另一个简单选择器序列和组合器会直接添加匹配约束,所以一个选择器的受体集合是(此选择器)此选择器的最后一个简单选择器序列所表示元素的子集。

空的选择器不包含任何简单选择器序列和伪元素,它是无效选择器。
选择器中的字符可以被反斜杠转义,与CSS具有相同的转换规则。(CSS21,https://www.w3.org/TR/2011/REC-css3-selectors-20110929/#CSS21)。

某些选择器支持命名空间前缀。使用选择器的语言需要对命名空间前缀的声明机制进行说明。如果某个语言没有说明一个命名空间前缀声明的机制,那么将不会有前缀被声明。在CSS中,命名空间前缀被 @namespace 规则声明。[ CSS3NAMESPACE,https://www.w3.org/TR/2011/REC-css3-selectors-20110929/#CSS3NAMESPACE ]

5. 选择器组

一个逗号分隔的选择器列表表示了被列表中每个独立选择器所选择元素的并集。(逗号是U+002C)例如,在CSS中一些选择器共享相同的声明,他们可能被归入一个逗号分割的列表。空白符可能出现在逗号之前和(或)之后。

CSS 示例:

在示例中,我们浓缩三条规则到一条规则中,因此:

h1 { font-family: sans-serif }
h2 { font-family: sans-serif }
h3 { font-family: sans-serif }

等价于:

h1, h2, h3 { font-family: sans-serif }

注意:等价之所以成立是因为例子中所有的选择器是有效选择器。任何一个选择器是无效的,那么整个选择器组将是无效的。这将使选择器组中所有三个元素的规则都无效,而在前一种情况下只有一条规则会无效。

无效 CSS 示例:

h1 { font-family: sans-serif }
h2..foo { font-family: sans-serif }
h3 { font-family: sans-serif }

不等价于:

h1, h2..foo, h3 { font-family: sans-serif }

因为选择器组 (h1, h2..foo, h3) 整个是无效的,所有的样式将被忽略。 (当选择器没有被分组, 只有h2..foo的规则被忽略)。

6.简单选择器

6.1.类型选择器

一个类型选择器被文档语言元素的类型名组成,是CSS限定名中的关键字。一个类型选择器表示文档树中元素类型的一个实例。

示例:

下面的选择器表示了文档树中的h1元素:

h1

6.1.1. 类型选择器和命名空间

类型选择器允许添加一个可选择的命名空间:元素名称开头可能被添加一个已经被预先定义的命名空间名作为前缀,被命名空间分隔符 竖线(U+007C, |)分割。

命名空间组件可能左边是空的(在命名空间分隔符前没有前缀)来表明选择器仅仅作用于没有命名空间的元素。

一个星号可能被用于命名空间前缀,表明这个选择器作用于任何命名空间的元素(包括没有命名空间的元素)。

元素类型选择器没有命名空间组件(没有命名空间分隔符)表示忽略命名空间(等价于*|),除非一个默认命名空间被声明。如果一个默认命名空间被声明,前面的选择器仅仅作用于默认命名空间下的元素。

如果一个类型选择器包含没有预先定义的命名空间前缀,将是一个无效选择器。
在支持命名空间的客户端中,元素类型选择器的名称部分仅仅和本地元素限定名竞争。

总结:

  • ns|E 命名空间ns中的名称为E的元素。

  • *|E 任何命名空间中名称为E的元素,包含没有命名空间的元素。

  • |E 没有命名空间的名称为E的元素。

  • E 如果没有默认命名空间,等价于*|E。否则等价于ns|Ens是默认命名空间。

CSS 示例:

@namespace foo url(http://www.example.com);
foo|h1 { color: blue } /* 第一条规则 */
foo|* { color: yellow } /* 第二条规则 */
|h1 { color: red } /* ...*/
*|h1 { color: green }
h1 { color: green }

第一条规则(不包括@namespace这行)将会仅仅匹配"http://www.example.com" 命名空间下的h1元素。

第二条规则将会匹配命名空间 "http://www.example.com" 下的所有元素。

第三条规则将会匹配没有命名空间中的h1元素。

第四条规则将会匹配任何命名空间中的h1元素(包括没有命名空间的h1元素)。

最后一条等同于第四条,因为没有默认命名空间被定义。

6.2. 全局选择器

全局选择器作为CSS限定名被写为星号(* U+002A),表示任何元素类型。它表示一个在文档树中且在任何命名空间中(包括没有命名空间,在没有默认命名空间时)的单一元素。如果存在一个默认命名空间,参照下面 全局选择器和命名空间 部分。

如果一个被表示为*的全局选择器(例如没有命名空间前缀)不是一个简单选择器序列唯一的组件或者直接被伪元素跟随,那么*可能被省略并且暗指全局选择器是存在的。

示例:

*[hreflang|=en][hreflang|=en] 等价。
*.warning.warning 等价。
*#myid#myid 等价。

注解:建议不要省略*,因为这可以减少潜在的混乱,例如:div :first-childdiv:first-child。 在这里, div *:first-child 更易读。

6.2.1. 全局选择器和命名空间

全局选择器允许一个可选的命名空间组件。像下面这样使用:

  • ns|* 命名空间ns下所有元素。

  • *|* 所有元素。

  • |* 没有命名空间的所有元素。

  • \* 如果不存在默认命名空间,这等价于*|*。否则等价于ns|*ns是默认命名空间。

如果一个全局选择器包含一个没有被预先声明的命名空间前缀,这个选择器是无效的。

6.3.属性选择器

选择器允许表示一个元素的属性。当选择器去匹配一个元素,属性选择器会匹配某个具有和属性选择器所表示属性相同属性的元素。

6.3.1. 属性存在和值选择器

CSS2引入了四个属性选择器:

[att]

表示一个元素具有att属性,不管值是什么。

[att=val]

表示一个元素具有att属性,并且其值是val。

[att~=val]

表示一个元素具有att属性,它的值是空白符分割的单词序列,其中一个单词是val。如果val包含空白符,它不代表任何东西(因为单词序列是由空白符分割的)。如果val是空字符串,它也不代表任何东西。

[att|=val]

表示一个元素具有att属性,他的值是val或由val开头紧紧跟随- (U+002D)。这主要是为了允许语言子编码匹配(例如HTML中a元素的hreflang),它在BCP 47(https://www.w3.org/TR/2011/REC-css3-selectors-20110929/#BCP47)或它的衍生物中被描述。

属性值必须是CSS标识符或者字符串。属性名称和值的大小写是否敏感依赖于文档语言。

示例:

下面的属性选择器表示一个具有title属性的h1元素,无论它的值是什么:

h1[title]

下面的选择器表示一个具有class属性的span对象,并且它的值是example:

span[class="example"]

多重属性选择器可以被用于表示一个对象的多个属性,或同一属性的一些状态。这里,选择器表示了一个span元素,它的hello属性具有值Cleveland并且这个元素的goodbye属性具有值Columbus:

span[hello="Cleveland"][goodbye="Columbus"]

下面的CSS规则表明"=""~="的不同。第一个选择器会选择一个带有rel属性且值为"copyright copyleft copyeditor"的a元素。第二个选择器仅仅会选择href属性值伪"http://www.w3.org/"的a元素:

a[rel~="copyright"] { ... }
a[href="http://www.w3.org/"] { ... }

下面的选择器表示一个具有hreflang并且值伪fr的a元素:

a[hreflang=fr]

下面选择器表示具有以en开头的hreflang属性的a元素,值可以是"en", "en-US", 和 "en-scouse"等:
a[hreflang|="en"]

下面的选择器表示一个DIALOGUE元素,它具有两个不同值中的一个:

DIALOGUE[character=romeo]
DIALOGUE[character=juliet]

6.3.2. 子字符串匹配属性选择器

三个附加的属性选择器被提供用来匹配属性值的子字符串。

[att^=val]

表示一个元素具有att属性,且值以val开头。如果val是空字符串,这个选择器不具有任何表示。

[att$=val]

表示一个元素具有att属性,且值以val结尾。如果val是空字符串,这个选择器不具有任何表示。

[att*=val]

表示一个元素具有att属性,且值包含val。如果val是空字符串,这个选择器不具有任何表示。

属性值必须是CSS标识符或字符串。属性名称的大小写敏感性依据文档语言。

示例:

下面的选择器表示一个HTML对象,是一个image:

object[type^="image/"]

下面的选择器表示一个HTML锚点a,具有href属性且值以.html结尾L:

a[href$=".html"]

下面的选择器表示一个HTML段落有一个title属性且值包含hello:

p[title*="hello"]

6.3.3. 属性选择器和命名空间

属性选择器中的属性名是一个CSS限定名:一个被预先声明的命名空间作为属性名的前缀,通过命名空间分隔符 竖线 (|)隔开。为了遵照XML中对命名空间的建议,默认命名空间不适用于属性,因此没有命名空间组件的属性选择器仅仅作用于没有命名空间的属性(等价于|attr)。星号可能被用在命名空间前缀表明选择器匹配所命名空间中的属性。

如果一个属性选择器的属性名具有没有预先声明的命名空间前缀,这将是个无效的选择器。

CSS 示例:

@namespace foo "http://www.example.com";
[foo|att=val] { color: blue }
[*|att] { color: yellow }
[|att] { color: green }
[att] { color: green }

第一个规则将会匹配具有"http://www.example.com"命名空间下的att属性,且值伪val的元素。

第二个规则将会匹配具有att属性的元素,不管命名空间(包括空命名空间)。

最后两个规则是等价的,匹配具有无命名空间的att属性的元素

6.3.4. DTD中的默认属性值

属性选择器表示文档树中的属性值。文档树是怎样被构造的不属于选择器的范畴。在一些文档格式中默认属性值在DTD或其它地方被定义,但是这些属性值只有当他们出现在文档树中时才能被匹配。选择器必须被设计以便于无论默认属性是否在文档树中它们都能正常工作。

例如,一个XML UA可能但不一定去读取DTD的外部子集,但一定要在文档的内部子集上查找默认值(例如,在 [XML10] https://www.w3.org/TR/2011/REC-css3-selectors-20110929/#XML10 获取这些子集的定义。)在文档树中出现或不出现外部子集定义的属性默认值时取决于UA的。

一个识别出XML命名空间的UA可能但不一定使用它的知识去设置默认属性值,即使他们已经被表现在文档中。(例如,一个XHTML UA不一定去使用它的内建的XHTML DTD的知识。参照[XML-NAMES] https://www.w3.org/TR/2011/REC-css3-selectors-20110929/#XML-NAMES 获取XML1.0中命名空间的细节。)
注解:一般来说,实现会会略外部子集。这相当于XML定义的不验证处理器得行为。

示例:

考虑一个元素EXAMPLE具有一个属性radix,它具有默认值decimal。DTD片段可能是:

<!ATTLIST EXAMPLE radix (decimal,octal) "decimal">

如果样式表包含规则:

EXAMPLE[radix=decimal] { /*... 默认属性设置 ...*/ }
EXAMPLE[radix=octal] { /*... 其他设置...*/ }

第一条规则可能不会匹配radix属性为默认值的元素,也就是没有被明确设置。为了应对所有情形,对默认属性的属性选择器必须被取消掉:

EXAMPLE { /*... default property settings ...*/ }
EXAMPLE[radix=octal] { /*... other settings...*/ }

这里,因为选择器EXAMPLE[radix=octal]更加具体,第二条规则的样式声明会覆盖第一条规则。注意所有针对默认情况的属性声明都被非默认情况下的样式规则覆盖了。

6.4. 类选择器

使用HTML时,当表示class属性的时候开发者可能会用句点(period)符号(也称作”full stop”, U+002E, .)作为~=的替代。因此对于HTMl,div.valuediv[class~=value]意思是一样的。属性值必须直接跟随句点(.)。

如果UA能够通过命名空间定义的知识推断出哪个是class属性,那么UA可能对XML文档应用带有句点语法的选择器。

CSS 示例:

对于所有具有class~="pastoral"的选择器,我们可以这样定义:

*.pastoral { color: green } /* 所有元素具有 class~=pastoral */

或者:

.pastoral { color: green } /* 所有元素具有 class~=pastoral */

下面的标记仅仅对于具有class~=pastoral的h1元素:

H1.pastoral { color: green } /* H1 元素具有 class~=pastoral */

对于这条规则,下面第一行的h1不会具有绿色文字,第二行的h1会有:

<H1>Not green</H1>
<H1 class="pastoral">Very green</H1>

下面的规则匹配任何class值是由空白符分割的单词列表且包含pastoral和marine的p元素:

p.pastoral.marine { color: green }

这条规则匹配class="pastoral blue aqua marine"但不匹配class="pastoral blue"

注解:因为CSS为class属性赋予了强大的功能,开发者可以直接基于元素设计他们自己的“文档语言”而不使用被广泛使用的表示(例如HTML中的DIV和SPAN)并且通过class属性来设置样式。开发者应该避免这种实践,因为文档语言的结构化元素通常是可辨识的而且具有通用语义,开发者自定义的类可能做不到这点。

6.5. ID选择器

文档语言可能包含声明为ID的属性。ID之所以特殊是因为无论ID所在的元素是什么类型,在文档中没有两个ID属性具有相同的值。无论哪个文档语言,ID可以作为元素的唯一标识。在HTML中所有ID属性叫做”id”,XML应用中ID属性可能有不同的名字,但是具有同样的约束。

一个ID类型属性可以允许开发者在文档树中标识一个元素。一个ID选择器包含一个井号 (U+0023, #) 后面直接跟着ID值,必须是一个CSS标识符。一个ID选择器表示一个元素,它的ID能够匹配到ID选择器中的ID。

选择器不说明UA怎样知晓元素的ID属性。UA可能例如读取文档的DTD,具有信息的硬编码或询问用户来获取这些信息。

示例:

下面的ID选择器表示一个h1元素具有ID类型属性,且值为chapter1:

h1#chapter1

下面的ID选择器表示一个任意元素具有ID类型属性,且值为chapter1:

#chapter1

下面的选择器表示任何元素具有ID类型属性,且值为z98y:

*#z98y

如果一个元素具有多个ID属性,所有的它们必须被当作ID集合以提供给ID选择器。可以通过xml:id,DOM 3 Core,XML DTDs 和 namespace-specific 等知识来实现。

6.6. 伪类

伪类的概念被引入用来选择那些不存在于文档树或无法通过其他简单选择器选择的内容。

一个伪类总是包含一个冒号(:)后跟伪类名和可选的小括号中的值。

伪类允许出现在选择器中的所有简单选择器序列中。伪类被允许出现在简单选择器序列中第一个类型选择器或全局选择器后的任何地方。伪类的名字是大小写不敏感的。一些伪类是互相排斥的。伪类可能是动态的,当用户操作文档时一个元素可能获得或失去一个伪类。

6.6.1. 动态伪类

动态伪类根据元素特征分类,不同于他们的名称、属性和内容,原则上特征不能从文档树得出。

动态伪类不会出现在文档源或文档树中。

用户代理一般将已访问过的链接和未访问的链接分开表示。选择器提供伪类:link:visited来区分他们。

  • :link伪类表示还没有访问过的链接

  • :visited伪类表示已经访问过的链接

一段时间后,浏览器可能会将已访问链接返回到未访问状态。
这两个状态是互相排斥的。

示例:

下面的选择器表示已访问的具有external class的a元素:

a.external:visited

注解:这可能让样式表开发者在未经用户同意的情况下探测用户已经访问过哪些网站。

UA可能因此将所有链接设置为未访问,或实现其他策略去避免用户隐私泄露。

6.6.1.2. 用户动作伪类 :hover, :active, 和 :focus

交互性用户代理时有会改变渲染以响应用户操作。选择器提供三个伪类来响应用户操作。

  • :hover伪类:当用户通过指针设备指定一个元素,但不一定激活它。例如,当光标(鼠标指针)停在元素上方时可视化用户代理可以激活这个伪类。不支持交互式媒体的用户代理不必支持这个伪类。

  • :active伪类:用户激活元素时激活这个伪类。例如用户在元素上单击鼠标。

  • :focus伪类:当元素获取焦点时这个伪类被激活(从键盘或鼠标或其他设备获取输入)。

文档语言或特殊实现会限制某些元素能够捕获:active:focus

这些伪类不是互相排斥的。一个元素可能同时匹配到多个伪类。

当一个元素处于:active:hover时,选择器没有定义其父元素是否也处于同样的状态。

注解:如果一个元素处于:hover作用是因为它的子元素被指针设备所指向,这时这个父元素可能并没有被指针元素所指向。

示例:

a:link /* 未访问过的链接 */
a:visited /* 已访问过的链接 */
a:hover /* 用户悬停 */
a:active /* 活动中的链接 */

组合动态伪类的例子

a:focus
a:focus:hover
最后一个选择器匹配同时处在:focus:hover状态下的元素。

注解:一个元素可以同时处在:visited:active(或 :link:active)。

6.6.2. 目标伪类:target

有些URI引用一个资源中的一个地址。这类URI以井号(#)结束并跟着一个锚标识符(被称作 片段标识符 fragment identifier)。

具有片段标识符的URI链接到文档内的某一个元素,就是目标元素。例如这个URI指向HTML文档内叫做section_2的锚点:

http://example.com/html/top.html#section_2

一个目标元素可以被:target伪类表示。如果文档的URI没有片段标识符,那么文档不存在目标元素。

示例:

p.note:target

这个选择器表示了一个做为文档目标元素且classnotep元素。

CSS 示例:

下面,:target伪类用来将目标元素变成红色并且在它之前放置一个图像:

*:target { color : red }
*:target::before { content : url(target.png) }

6.6.3. 语言伪类:lang

如果文档语言描述了如何确定一个元素的自然语言,那么将有可能实现一个表示特定语言的元素的选择器。例如,在HTML中语言可以被lang属性和meta元素中的可能存在的一些信息组合表示或在协议中(例如HTTP头部)表示。XML使用叫做xml:lang的属性,并且其他文档语言可能使用其他方法来确定语言。

伪类:lang(C)表示一个使用语言C的元素。无论元素的语言值(如果必要可遵循BCP 47关键字)等于C,或是以C开头跟随 - (U+002D)都将被匹配。C的匹配反对元素的语言值被表现为大小写不敏感。C不必是一个有效的语言名。

C必须是一个有效的CSS标识符并且不可以为空。(否则,选择器是无效的)。

注解:建议使用BCP 47或其衍生品中的代码来表示文档和协议中的语言,在基于XML的文档中使用xml:lang语义。

示例:

前两个选择器表示一个应用Belgian FrenchGerman语言的HTML文档。后两个选择器表示任意Belgian FrenchGerman语言元素中的q元素:

html:lang(fr-be)
html:lang(de)
:lang(fr-be) > q
:lang(de) > q

:lang(C)|=操作符的区别在于|=操作符仅仅表示对元素指定属性的比较,而:lang(C)伪类使用UA的知识在文档语义上进行比较。

在这个HTML示例中, 仅仅BODY匹配[lang|=fr](因为它具有LANG属性)但是BODY和P都匹配:lang(fr)(因为他们都使用法语)。P不匹配[lang|=fr]因为它没有LANG属性:

<body lang=fr>
<p>Je suis français.</p>
</body>

6.6.4. UI元素状态伪类

6.6.4.1. :enabled:disabled伪类

:enabled伪类表示处在可用状态下的用户接口元素。这些元素具有与不可用相对的状态。

相反的,:disabled伪类表示用户接口元素在不可用状态。这些元素具有与可用相对的状态。

用户接口元素、可用与不可用状态是依赖于自然语言的。在一个典型的文档中大多数元素既不是:enabled也不是:disabled的。

注解:CSS中可能影响用户与UI元素交互的属性不会影响:enabled:disabled的匹配。例如displayvisibility属性不会影响元素的enabled/disabled状态。

6.6.4.2. :checked伪类

单选和多选元素可以被用户开关。一些菜单项目在用户选择他们时会处在选中状态。当这些元素处于开(on)状态,他们会匹配:checked伪类。:checked伪类本质上是动态的,他们随着用户操作而改变。因为它可以以文档中存在的语义属性作为依据,所以它可以匹配所有的媒体。例如:checked伪类最初匹配HTML4中具有selectedchecked的元素(他们被描述在Section 17.2.1 of HTML4,https://www.w3.org/TR/REC-html40/interact/forms.html#h-17.2.1)。用户可以关闭(toggle “off”)这些元素,这将使:checked伪类不再匹配。

6.6.4.3. :indeterminate伪类

注解:单选和多选元素可以被用户开关,但一些时候它们处在不确定状态,既不是选中也不是非选中。元素属性和DOM操作可能导致这种情况。

这个手册的之后版本可能介绍:indeterminate伪类对这些元素的作用。

6.6.5. 结构化伪类

选择器通过结构化伪类的概念来进行基于文档中额外信息的不能被其他简单选择器或组合器表示的匹配。
在计算元素位于其父元素的子元素列表中的位置时,独立的文字或其他非元素节点是不被计算的且索引是从1开始的。

6.6.5.1. :root伪类

:root伪类表示作为文档根的元素。在HTML 4中总是HTML元素。

6.6.5.2. :nth-child()伪类

:nth-child(an+b)伪类表示一个元素它在文档树中有an+b-1个前兄弟节点,n可以为任何正数或0,并且有一个父元素。a和b要大于0。这有效的将子元素按a个元素进行分组(最后一组包含余数个元素),并且选择每一组的第b个元素。a和b必须为整数(正数,负数或0)。第一个子元素的索引是1。

此外,:nth-child()可以用oddeven作为参数。odd相当于2n+1,even相当于2n。

:nth-child()必须符合下面的语法,其中INTEGER匹配[0-9]+,其他标记参见Lexical scanner(https://www.w3.org/TR/2011/REC-css3-selectors-20110929/#lex)的10.2小节:

nth
: S* [ ['-'|'+']? INTEGER? {N} [ S* ['-'|'+'] S* INTEGER ]? |
['-'|'+']? INTEGER | {O}{D}{D} | {E}{V}{E}{N} ] S*
;
示例:

tr:nth-child(2n+1) /* 表示HTML中table的奇数行 */
tr:nth-child(odd) /* 同上 */
tr:nth-child(2n+0) /* 表示HTML中table的偶数行 */
tr:nth-child(even) /* 同上 */

/* 通过CSS修改段落颜色 */
p:nth-child(4n+1) { color: navy; }
p:nth-child(4n+2) { color: green; }
p:nth-child(4n+3) { color: maroon; }
p:nth-child(4n+4) { color: purple; }

当b前面存在负号,那么正号必须被移除,也就是说被负号替代以表示b是个负数。

示例:

:nth-child(10n-1) /* 表示第9,第19,第29以此类推的元素*/
:nth-child(10n+9) /* 同上 */
:nth-child(10n+-1) /* 无效的语法,会被忽略 */

当a=0时ab部分应被忽略(除非b部分已经被忽略了)。当an不存在并且b是非负数,b前的正号(当存在时)可以被忽略。这类似于:nth-child(b)。

示例:

foo:nth-child(0n+5) /* 表示一个处在第五个的foo元素 */
foo:nth-child(5) /* 同上 */

当a=1或a=-1,这个数字可以被省略。

示例:

下面的选择器等价:

bar:nth-child(1n+0) /* 选择所有bar元素, 优先级 (0,1,1) */
bar:nth-child(n+0) /* 同上 */
bar:nth-child(n) /* 同上 */
bar /* 同上,但是优先级更低 (0,0,1) */

如果b=0,那么每一个第a个元素被选取。这种情况下,+b(或-b)部分可能被省略除非a部分已经被省略了。

示例:

tr:nth-child(2n+0) /* 表示HTML中table的每一个偶数行 */
tr:nth-child(2n) /* 同上 */

空白符被允许出现在“(”后,“)”前,并且当an和b同时出现时空白符可以出在线+或-的两边。

空白符的有效例子:

:nth-child( 3n + 1 )
:nth-child( +3n - 2 )
:nth-child( -n+ 6)
:nth-child( +6 )

空白符的无效例子:

:nth-child(3 n)
:nth-child(+ 2n)
:nth-child(+ 2)

a和b都为0时,这个伪类不表示文档树中的任何元素。

a可以是负数,但是an+b只能是正数,对于n>=0,可能表示文档树中的一个元素。

示例:

html|tr:nth-child(-n+6) /* 表示XHTML中table的前6行 */
6.6.5.3. :nth-last-child()伪类

:nth-last-child(an+b)伪类表示一个元素,在文档树中这个元素之后有an+b-1个兄弟元素。n可以为任何正数或0,并且有一个父元素。参数的定义参照:nth-child()。同样可以接受oddeven作为参数。

示例:

tr:nth-last-child(-n+2) /* 表示HTML中table的最后2行 */

foo:nth-last-child(odd) /* 表示父元素中的所有奇数元素,从后往前计算*/
6.6.5.4. :nth-of-type() 伪类

:nth-of-type(an+b)伪类表示一个元素在文档树中在这个元素之前具有an+b-1个和此元素相同元素名的兄弟元素,n可以为任何正数或0,并且具有父元素。 参数的定义参照:nth-child()。同样可以接受oddeven作为参数。

CSS 示例:

这允许开发者修改悬浮图像的位置:

img:nth-of-type(2n+1) { float: right; }
img:nth-of-type(2n) { float: left; }
6.6.5.5. :nth-last-of-type()伪类

:nth-last-of-type(an+b)伪类表示一个元素在文档树中在这个元素之后具有an+b-1个和此元素相同元素名的兄弟元素,n可以为任何正数或0,并且具有父元素。 参数的定义参照:nth-child()。同样可以接受oddeven作为参数。

示例:

表示XHTML的body中所有h2元素,除了第一个和最后一个

body > h2:nth-of-type(n+2):nth-last-of-type(n+2)

在这个示例中,用样可以使用:not(),虽然选择器是一样长的:

body > h2:not(:first-of-type):not(:last-of-type)
6.6.5.6. :first-child伪类

:nth-child(1)相同。:first-child表示第一个子元素。

示例:

这个选择器表示div元素中的p元素,且这个p元素是第一个子元素:

div > p:first-child

这个选择器表示下面片段中div中的p元素:

<p> The last P before the note.</p>
<div class="note">
<p> The first P inside the note.</p>
</div>

但是不表示下面片段中的第二个p元素:
but cannot represent the second p in the following fragment:
<p> The last P before the note.</p>
<div class="note">
<h2> Note </h2>
<p> The first P inside the note.</p>
</div>

下面的两个选择器一般是等价的:

* > a:first-child /* a是任何元素的第一个子元素 */
a:first-child /* 当a不是根元素时同上 */
6.6.5.7. :last-child伪类

:nth-last-child(1):last-child表示一个元素中的最后一个子元素。

示例:

这个选择器表示一个有序列表ol中的最后一个条目li

ol > li:last-child
6.6.5.8. :first-of-type 伪类

:nth-of-type(1):first-of-type伪类表示具有相同元素类型的兄弟节点中的第一个节点。

示例:

下面的选择器表示一个在列表dl中的标题dt,这个dt是与它相同类型的兄弟节点中的第一个节点:

dl dt:first-of-type

这表示了下面的头两个dt元素,但不能表示第三个dt元素:

<dl>
<dt>gigogne</dt>
<dd>
<dl>
<dt>fusée</dt>
<dd>multistage rocket</dd>
<dt>table</dt>
<dd>nest of tables</dd>
</dl>
</dd>
</dl>
6.6.5.9. :last-of-type

:nth-last-of-type(1):last-of-type伪类表示具有相同元素类型的兄弟节点中的最后一个节点。

示例:

下面的选择器表示table行tr中的最后一个数据单元td:

tr > td:last-of-type
6.6.5.10. :only-child伪类

表示某个是其父元素中的唯一元素的元素。同:first-child:last-child:nth-child(1):nth-last-child(1), 但是具有更低的优先级。

6.6.5.11. :only-of-type伪类

表示某个父元素中子元素,父元素不存在与此子元素同类的子元素。同:first-of-type:last-of-type:nth-of-type(1):nth-last-of-type(1),但是具有更低的优先级。

6.6.5.12. :empty伪类

:empty伪类表示一个元素根本没有子元素。在文档树中,仅仅元素节点和内容节点(例如DOM中的text节点,CDATA节点,和实体引用,https://www.w3.org/TR/2011/REC-css3-selectors-20110929/#DOM-LEVEL-3-CORE)具有非0长度的数据时,会影响是否为空。注释,处理指令和其他节点一定不会对是否为空产生影响。

示例:

p:empty 对下面的片段是有效的:

<p></p>

foo:empty 对下面的片段是无效的:

<foo>bar</foo>
<foo><bar>bla</bar></foo>
<foo>this is not <bar>:empty</bar></foo>

6.6.6. 空白

这一节是故意留白的,之前是:contains()伪类。

6.6.7. 拒绝伪类

拒绝伪类:not(X)是一个将简单选择器作为参数的功能符。它表示非它的参数所表示的元素。

拒绝伪类不可嵌套,:not(:not(...))是无效的。注意因为伪元素不是简单选择器,所以他们不可以作为:not()的参数。

示例:

这个选择器选择HTML文档中所有button除了处于disabled状态的:

button:not([DISABLED])

下面的选择器选择所有元素除了FOO元素:

*:not(FOO)

下面的选择器组表示所有HTML元素除了链接:

html|*:not(:link):not(:visited)

默认命名空间声明不会影响拒绝伪类的参数,除非参数是个全局选择器或一个类型选择器。

示例:

假定默认命名空间是"http://example.com/",下面的选择器表示所有不在这个命名空间中的元素:

*|*:not(*)

下面的选择器匹配任何没有被指向的元素,不管它的命名空间是什么。特别指出,这不会限制仅仅选择默认命名空间下没有被指向的元素,并且不再命名空间中的被指向的元素,不会被这个规则匹配。

*|*:not(:hover)

注解::not()伪类允许表示没有价值的选择器,例如:not(*|*),这不表示任何元素,或者foo:not(bar),这等价于foo但是具有更高优先级。

7.伪元素

伪元素创建超越文档语言定义的文档树的抽象概念。例如,文档语言没有提供对一个元素内容的第一个字符或第一行的访问机制。伪元素允许开发者访问这些原本难以访问的信息。伪元素同样可以提供给开发者访问源文档中不存在内容的途径(例如::before::after伪元素提供了生成内容的方式)。

伪元素由两个冒号::及紧随其后的名字组成。

::被这个文档引入是为了提供区别伪类和伪元素。为了和之前的样式表兼容,用户代理必须同样允许之前在CSS 1和2级中的单冒号表示方法(如:first-line,:first-letter,:before:after)。这个兼容不应用于这个手册中提到的新的伪元素。

每一个选择器仅仅可能出现一个伪元素,并且如果存在的话必须位于简单选择器序列的最后。注意:这个手册之后的版本可能允许在一个选择器中存在多个伪元素。

7.1.::first-line伪元素

::first-line伪元素表示一个元素中的第一个格式化行。

CSS 示例:

p::first-line { text-transform: uppercase }

上面的规则表示改变所有p元素中第一行的字幕为大写。
选择器p::first-line不匹配任何真正的文档元素。它匹配一个伪元素,这个伪元素会被用户代理插入到每个p的开始。

注意第一行的长度取决于很多因素,包括页宽、字体大小等等。

因此,一个源HTML段落是这样的:

<P>This is a somewhat long HTML 
paragraph that will be broken into several
lines. The first line will be identified
by a fictional tag sequence. The other lines
will be treated as ordinary lines in the
paragraph.</P>

这些行可能被打断为:

THIS IS A SOMEWHAT LONG HTML PARAGRAPH THAT
will be broken into several lines. The first
line will be identified by a fictional tag
sequence. The other lines will be treated as
ordinary lines in the paragraph.

这个段落可能被用户代理“重写”为包含了::first-line的虚构的标签序列。这个虚构的标签序列帮助展示了属性是怎样继承的:

<P><P::first-line> This is a somewhat long HTML 
paragraph that </P::first-line> will be broken into several
lines. The first line will be identified
by a fictional tag sequence. The other lines
will be treated as ordinary lines in the
paragraph.</P>

如果一个伪元素打断了一个真实的元素,所期望的效果经常可以被一个关闭并且重新打开那个元素的虚构标签序列所实现。因此,如果我们用一个span元素标记前面的元素:

<P><SPAN class="test"> This is a somewhat long HTML
paragraph that will be broken into several
lines.</SPAN> The first line will be identified
by a fictional tag sequence. The other lines
will be treated as ordinary lines in the
paragraph.</P>

用户代理在添加::first-line标签序列时会为span添加开始和结束标签:

<P><P::first-line><SPAN class="test"> This is a
somewhat long HTML
paragraph that will </SPAN></P::first-line><SPAN class="test"> be
broken into several
lines.</SPAN> The first line will be identified
by a fictional tag sequence. The other lines
will be treated as ordinary lines in the
paragraph.</P>

7.1.1. CSS中定义的第一个格式化行(first formatted line)

在CSS中,::first-line伪元素仅仅在附属于块容器时才有效果,例如块盒子,内联块,表格标题或表格元素。

在同一流中,一个元素的第一个格式化行可能出现在块级后代中。(例如,一个块级后代没有因为浮动和定位而脱离流)。例如,<DIV><P>This line...</P></DIV>中DIV的第一行就是P的第一行(假定P和DIV都是块级)。

表格元素或内联块不能作为祖先元素的第一个格式化行。因此,<DIV><P STYLE="display: inline-block">Hello<BR>Goodbye</P> etcetera</DIV>中DIV的第一个格式化行不是“Hello”。

注意:在片段<p><br>First...中p的第一个格式化行不包含任何字母(假定使用HTML4中br的默认样式)。“First”不是第一个格式化行。

UA应该将::first-line的虚拟开始标签嵌套于最内部的闭合块级元素中。(因为CSS1和CSS2对这点沉默,开发者不要相信这个行为。)

例如,下面段落

<DIV>
<P>First paragraph</P>
<P>Second paragraph</P>
</DIV>

的虚拟标签序列是

<DIV>
<P><DIV::first-line><P::first-line>First paragraph</P::first-line></DIV::first-line></P>
<P><P::first-line>Second paragraph</P::first-line></P>
</DIV>

::first-line伪元素类似于一个内联元素,但是具有一些约束。下面的CSS属性可以作用于一个::first-line伪元素:字体属性,颜色属性,背景属性,word-spacing, letter-spacing, text-decoration, vertical-align, text-transform, line-height。UA可能实现其他属性。

在CSS继承中,出现在第一行的子元素的某些部分仅仅从::first-line伪元素继承适用于::first-line伪元素的属性。其他属性继承于第一行伪元素的非伪元素父元素。(子元素的不出现在第一行的部分总是继承于父元素)。

7.2.:first-letter伪元素

::first-letter伪元素表示一个元素的第一个字母,如果在这行上它前面没有任何其他内容(例如图片和内联表格)。::first-letter伪元素可能被用于开头字母大写和首字下沉这些通用的印刷效果。

标点符号(例如Unicode中定义的”open” (Ps), “close” (Pe), “initial” (Pi). “final” (Pf) 和 “other” (Po) 标点符号类),如果他们出现在在首字母之前或之后也应该被包括进去。

CSS第三级选择器 Selectors Level 3 文档翻译

如果首字母是数字,::first-letter同样生效,例如”67 million dollars is a lot of money.”中的“6”。

注解:一些情况下::first-letter伪元素在第一行上不应该仅仅包括第一个非标点符号字符。例如,组合字符必须和组成它的字符保持完整。另外,一些语言关于对待某些字母组合可能有特殊的规则。UA对于::first-letter的定义应该至少包含UAX29中默认的字母集合和其他更多的适当内容。例如,如果字母组合“ij”出现在一个元素的开始,两个字母都应该被认为在::first-letter伪元素中。

如果应该组成::first-letter的字母不在一个元素中,例如<p>'<em>T...中的“’T”,UA可能为其中一个或两个字母创建::first-letter伪元素,或仅仅什么都不创建。

同样的,如果块中的第一个字母没有在行的开始(例如因为双向重排序),此时UA不需要创建伪元素。

示例:

下面的CSS和HTML示例阐明了重叠的伪元素可能相互影响。配一个P元素的第一个字母将会变成绿色并且字体大小伪24pt。第一个格式化行的其他内容将会变成蓝色,剩下的内容为红色:

p { color: red; font-size: 12pt }
p::first-letter { color: green; font-size: 200% }
p::first-line { color: blue }

<P>Some text that ends up on two lines</P>

假定在词"ends"前有一个换行,这一段虚构标签序列将会是:

<P>
<P::first-line>
<P::first-letter>
S
</P::first-letter>ome text that
</P::first-line>
ends up on two lines
</P>

注意::first-letter元素在::first-line元素内。::first-line的属性被::first-letter继承,但是如果在::first-letter中设置了相同的属性,那么将会被重写。

首字母必须出现在第一个格式化行上。例如,在这个HTML片段中<p><br>First...第一行不包含任何字母并且::first-letter不匹配任何东西(假如br是HTML4中的默认样式)。特别指出,它不匹配“First”中的“F”。

7.2.1. CSS中的应用

在CSS中,::first-letter伪元素在类块容器中生效,例如blocklist-itemtable-celltable-captioninline-block元素。注意:这个手册的未来版本可能允许这个伪元素在更多显示类型中生效。

::first-letter伪元素可以被用于所有此类包含文字,或者在相同文档流中的后代包含文字的元素。一个UA应该认为::first-letter的虚拟开始标签置于元素第一段文字前,即使第一段文字在一个后代中。

示例:

下面这段HTML片段

<div>
<p>The first text.

的虚拟标签序列是

<div>
<p><div::first-letter><p::first-letter>T</...></...>he first text.

在CSS中table-cellinline-block的第一个字母不能作为祖先元素的第一个字母。因此,<DIV><P STYLE="display: inline-block">Hello<BR>Goodbye</P> etcetera</DIV>中DIV的第一个字母不是“H”。事实上,DIV没有首字母。

如果一个元素是一个列表项目(display: list-item),::first-letter应用于标记后主要盒子的首字母。当具有list-style-position: inside UA可能会忽略列表项目上的::first-letter。如果一个元素有::before或者::after内容,::first-letter的作用范围应包括这些内容。

示例:

p::before {content: "Note: "}生效时, p::first-letter 匹配“Note”中的“N”。

在CSS中当float属性是none::first-line伪元素相当于一个内联元素。否则它是浮动元素。下面的属性对::first-letter生效:字体属性,text-decoration, text-transform, letter-spacing, word-spacing (当适用时), line-height, float, vertical-align (仅当floatnone),边距属性,内距属性,边框属性,颜色属性,背景属性。UA可能使得其他属性也适用。为了使得UA渲染正确的印刷用首字下沉或首字大写,UA可能根据字幕的形状选择行高、宽度和高度,这不像普通元素那样。

示例:

这个CSS和HTML例子展示了一个首字大写的可能渲染。注意::first-letter继承了‘line-height’为1.1,但是这个例子中UA为首字计算了不同的高度,所以这没有在前两行之间导致任何不必要的空白。同样注意首字母的虚构开始标签是在span中的,首字母的字体粗细是正常的,不像span那样是粗的:

p { line-height: 1.1 }
p::first-letter { font-size: 3em; font-weight: normal }
span { font-weight: bold }
...
<p><span>Het hemelsche</span> gerecht heeft zich ten lange lesten<br>
Erbarremt over my en mijn benaeuwde vesten<br>
En arme burgery, en op mijn volcx gebed<br>
En dagelix geschrey de bange stad ontzet.

CSS第三级选择器 Selectors Level 3 文档翻译

下面的CSS会制造大约两行的首字下沉。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<HTML>
<HEAD>
<TITLE>Drop cap initial letter</TITLE>
<STYLE type="text/css">
P { font-size: 12pt; line-height: 1.2 }
P::first-letter { font-size: 200%; font-weight: bold; float: left }
SPAN { text-transform: uppercase }
</STYLE>
</HEAD>
<BODY>
<P><SPAN>The first</SPAN> few words of an article
in The Economist.</P>
</BODY>
</HTML>
如图:

CSS第三级选择器 Selectors Level 3 文档翻译


虚拟标签序列是:

<P>
<SPAN>
<P::first-letter>
T
</P::first-letter>he first
</SPAN>
few words of an article in the Economist.
</P>

注意,::first-letter伪元素标签(例如首字大写)的位置,而::first-line伪元素的开始标签被插入在块元素的开始标签右侧。

为了实现传统的首字下沉格式,用户代理可能估算字体大小,例如匹配基准线。同样,字符轮廓也会在格式化时被考虑。

7.3. 空白

这个小节被留白(之前用来定义::selection伪元素)。

7.4.::before::after伪类

::before::after伪类可以被用来描述在元素内容之前或之后生成内容。他们在CSS2.1中被描述(https://www.w3.org/TR/2011/REC-css3-selectors-20110929/#CSS21

::first-letter::first-line被用在包含::before::after生成元素的对象时,第一个字母或第一行包含这些生成内容。

8. 组合器

8.1. 后代组合器

有时,开发者可能想要选择器在树中描述一个元素是另一个元素的后代(例如 一个EM元素被包含在一个H1元素中)。后代组合器表示这样一个关系。一个后代组合器是由空白符分开的两个简单组合器序列组成的。选择器“A B”表示一个元素B是祖先A的任意后代。

示例:

考虑下面的选择器:

h1 em

它表示一个em元素作为一个h1元素的后代。这正确,有效并且局部的描述了下面的片段

<h1>This <span class="myclass">headline
is <em>very</em> important</span></h1>

下面的选择器

div * p

表示了p元素是div元素之后的第二代或更多代元素。注意*两侧的空白符不属于全局选择器。空白符是一个组合器表示div是某个元素的祖先,并且这个元素是p的祖先。

下面的选择器,组合了后代组合器和属性选择器,表示一个元素具有href属性并且在p之中,p在div之中。
div p *[href]

8.2. 子代组合器

一个子代组合器描述了两个元素间的父子关系。一个子代组合器用大于号表示(U+003E, >),并且分割两个简单选择器序列。

示例:

下面的选择器表示了一个p元素是body元素的子代。

body > p

下面的例子组合了后代组合器和子代组合器。

div ol>li p

它表示了一个p元素是一个li元素的后代。li一定是一个ol元素的子代。ol元素一定是div元素的后代。注意>两边的空白符被忽略了。

8.3. 兄弟组合器

有两个不同的兄弟组合器:相邻兄弟选择器和普通兄弟选择器。他们都会忽略非元素节点(例如元素间的文字)。

8.3.1. 相邻兄弟组合器

相邻兄弟组合器用加号表示 (U+002B, +),它分割两个简单选择器序列。在文档树中这两个序列具有相同的父节点并且第一个序列表示的元素紧紧在第二个序列表示的元素前。

示例:

下面的选择器表示一个p元素仅仅跟在一个math元素后:

math + p

下面的选择器在概念上类似上面的例子,只是它加了一个属性选择器——它给h1加了一个约束,就是它必须有class="opener"

h1.opener + h2

8.3.2. 一般兄弟选择器

一般兄弟选择器通过波浪号表示(U+007E, ~),它分割两个简单选择器序列。两个序列表示的元素要在同一个父元素下并且第一个序列表示的元素要在第二个序列表示的元素前(但不必是紧紧挨着)。

示例:

h1 ~ pre
表示一个pre元素跟在h1后。它是正确且有效的,但是只是一部分,适用于:

<h1>Definition of the function a</h1>
<p>Function a(x) has to be applied to all figures in the table.</p>
<pre>function a(x) = 12x/13.5</pre>

9. 计算一个选择器的优先级

一个选择器的优先级按照下面的方式计算:

  • 计算ID选择器的数量(记为a)

  • 计算类型选择器和伪元素选择器的数量(记为c)

  • 忽略全局选择器

  • 拒绝伪类中的选择器同样参与计算,但是拒绝伪类本身不参与伪类的计算。

把三个数字连起来a-b-c(在具有大基数的数字系统中)作为优先级。

示例:

* /* a=0 b=0 c=0 -> 优先级 = 0 */
LI /* a=0 b=0 c=1 -> 优先级 = 1 */
UL LI /* a=0 b=0 c=2 -> 优先级 = 2 */
UL OL+LI /* a=0 b=0 c=3 -> 优先级 = 3 */
H1 + *[REL=up] /* a=0 b=1 c=1 -> 优先级 = 11 */
UL OL LI.red /* a=0 b=1 c=3 -> 优先级 = 13 */
LI.red.level /* a=0 b=2 c=1 -> 优先级 = 21 */
#x34y /* a=1 b=0 c=0 -> 优先级 = 100 */
#s12:not(FOO) /* a=1 b=0 c=1 -> 优先级 = 101 */

注意:重复出现相同的简单选择器是允许的并且会增加优先级

注意:HTML style属性中的样式的优先级在CSS 2.1中被描述(https://www.w3.org/TR/2011/REC-css3-selectors-20110929/#CSS21

10.选择器语法

11.档案

12.一致性和要求

13.测试

14.后记

15.引用