由于对工作方式:nth-child()
和:nth-of-type()
工作的误解,这是一个非常普遍的问题。不幸的是,目前还没有基于选择的解决方案至今,因为选择器不提供一种方法来匹配基础上的模式,如奇数,偶数或任意选择相匹配的第n个孩子an+b
,其中a != 1
和b != 0
。这不仅限于类选择器,还包括属性选择器,取反和简单选择器的更复杂组合。
该:nth-child()
伪类计算中的元素都在同一母公司下的兄弟姐妹。它不只计算与选择器其余部分匹配的兄弟姐妹。同样,:nth-of-type()
伪类计数共享相同元素类型的兄弟姐妹,该元素类型引用HTML中的标签名称,而不是选择器的其余部分。
这也意味着,如果同一父级的所有子级都具有相同的元素类型,例如,在表体中其唯一的子级是tr
元素,或者列表元素的唯一的子级是li
元素,则:nth-child()
并且:nth-of-type()
将表现相同,即对于每一个值an+b
,:nth-child(an+b)
并且:nth-of-type(an+b)
将匹配相同的一组元素。
实际上,给定复合选择器中的所有简单选择器(包括诸如:nth-child()
和的伪类)都彼此独立:not()
工作,而不是查看与选择器其余部分匹配的元素子集。
这也意味着在每个单独的复合选择器1 中的简单选择器之间没有顺序的概念,这意味着例如以下两个选择器是等效的:
table.myClass tr.row:nth-child(odd)
table.myClass tr:nth-child(odd).row
翻译成英文,它们的意思是:
选择tr
符合以下所有独立条件的任何元素:
- 它是其父代的奇数子代;
- 它具有“行”类;和
- 它是
table
具有“ myClass”类的元素的后代。
(您会注意到我在这里使用的是无序列表,只是为了将要点指向家)
因为目前还没有纯CSS解决方案,所以您必须使用脚本来过滤元素并相应地应用样式或额外的类名。例如,以下是使用jQuery的常见解决方法(假定在表中仅填充了一个行组tr
):
$('table.myClass').each(function() {
// Note that, confusingly, jQuery's filter pseudos are 0-indexed
// while CSS :nth-child() is 1-indexed
$('tr.row:even').addClass('odd');
});
使用相应的CSS:
table.myClass tr.row.odd {
...
}
如果您使用诸如Selenium之类的自动化测试工具,或者使用诸如lxml之类的工具来处理HTML,则其中许多工具都可以将XPath用作替代方法:
//table[contains(concat(' ', @class, ' '), ' myClass ')]//tr[contains(concat(' ', @class, ' '), ' row ')][position() mod 2)=1]
其他使用不同技术的解决方案留给读者练习。这只是一个简短的,人为的示例。
对于它的价值,有人提议将:nth-child()
表示法的扩展名添加到选择器级别4,以达到选择与给定选择器匹配的第n个子代的特定目的。2
:nth-child()
再次由于选择器如何按照现有选择器语法规定的顺序彼此独立地操作,因此将作为选择项的筛选器提供给。因此,在您的情况下,它看起来像这样:
table.myClass tr:nth-child(odd of .row)
(精明的读者会立即注意到,应该这样做:nth-child(odd of tr.row)
,因为简单的选择器tr
也:nth-child()
彼此独立运行。这是接受选择器的功能性伪类的问题之一,我会选择一堆蠕虫相反,我将假设大多数站点tr
在表主体中除了元素作为彼此的同级元素外,将不具有其他任何元素,这将使两个选项在功能上等效。)
当然,作为全新规范中的全新提案,可能要等到几年后才能实现。同时,您必须坚持使用脚本,如上所述。
1 如果指定类型或通用选择器,则必须排在最前面。但是,这不会改变选择器的基本工作方式。只是语法上的怪异而已。
2 最初被提议为:nth-match()
,但是因为它仍然仅相对于其同级而不是与给定选择器匹配的所有其他元素都相对于一个元素进行计数,自2014年起,该元素已被重新用作现有元素的扩展:nth-child()
。