我可以将 :nth-child() 或 :nth-of-type() 与任意选择器结合使用吗?

Posted

技术标签:

【中文标题】我可以将 :nth-child() 或 :nth-of-type() 与任意选择器结合使用吗?【英文标题】:Can I combine :nth-child() or :nth-of-type() with an arbitrary selector? 【发布时间】:2021-03-07 09:02:12 【问题描述】:

有没有办法选择每个匹配(或不匹配)任意选择器的第 n 个子 ?例如,我想选择每个奇数表行,但在行的子集中:

table.myClass tr.row:nth-child(odd) 
  ...

<table class="myClass">
  <tr>
    <td>Row
  <tr class="row"> <!-- I want this -->
    <td>Row
  <tr class="row">
    <td>Row
  <tr class="row"> <!-- And this -->
    <td>Row
</table>

:nth-child() 似乎只计算所有tr 元素,无论它们是否属于“行”类,所以我最终得到一个甚至“行”元素而不是我正在寻找的两个。 :nth-of-type() 也会发生同样的事情。

谁能解释一下原因?

【问题讨论】:

截至 2021 年 10 月,指定了 nth-child(n of S)(其中 S 是选择器),但据我所知,目前仅在 Safari 中实现,参见例如developer.mozilla.org/en-US/docs/Web/CSS/:nth-child 【参考方案1】:

这是一个非常常见的问题,由于对:nth-child(An+B):nth-of-type() 工作方式的误解而出现。

在第 3 级选择器中,:nth-child() pseudo-class 计算同一父级下的 所有 同级元素中的元素。它不只计算与选择器其余部分匹配的兄弟姐妹。同样,:nth-of-type() pseudo-class 计算共享相同元素类型的兄弟姐妹,它指的是 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元素:

它是其父代的奇数子代; 它有“行”类;和 它是类“myClass”的table 元素的后代。

(你会注意到我在这里使用了一个无序列表,只是为了说明问题)

选择器级别 4 试图通过允许 :nth-child(An+B of S)2 接受任意选择器参数 S 来纠正此限制,这同样是由于选择器在复合选择器中如何相互独立地运行,如现有的选择器语法。所以在你的情况下,它看起来像这样:

table.myClass tr:nth-child(odd of .row)

当然,作为全新规范中的全新提案,这可能要到a few years down the road 才能实现。

与此同时,您必须使用脚本来过滤元素并相应地应用样式或额外的类名。例如,以下是使用 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 等自动化测试工具或使用 BeautifulSoup 等工具抓取 HTML,其中许多工具都允许 XPath 作为替代方案:

//table[contains(concat(' ', @class, ' '), ' myClass ')]//tr[contains(concat(' ', @class, ' '), ' row ')][position() mod 2)=1]

其他使用不同技术的解决方案留给读者作为练习;这只是一个简短的、人为的示例。


1如果指定类型或通用选择器,则必须先出现。然而,这并没有改变选择器的基本工作方式;这只不过是一个语法怪癖。

2这最初是作为:nth-match() 提出的,但是因为它仍然只相对于它的兄弟元素计算一个元素,而不是相对于与给定选择器匹配的所有其他元素,它有自 2014 年起,它被重新用作现有 :nth-child() 的扩展。

【讨论】:

“(你会注意到我在这里使用了一个无序列表,只是为了说明问题)”我希望更多的人在他们使用有序子弹和无序子弹时会慎重考虑。谢谢你的回答。 @The Red Pea:我最大的 HTML 宠儿之一:“按从最高/最低到最低/最高的顺序:”后跟一个无序列表。我的意思是来吧,认真的吗?【参考方案2】:

不是真的..

quote from the docs

:nth-child 伪类匹配一个 有一个+b-1 兄弟的元素 在文档树中之前,对于 给定 n 的正值或零值, 并且有一个父元素。

它是一个自己的选择器,不与类结合。在您的规则中,它只需要同时满足两个选择器,因此如果 :nth-child(even) 表行也恰好有 .row 类,它将显示它们。

【讨论】:

【参考方案3】:

nth-of-type根据同类型元素的索引工作,而nth-child无论是什么类型的兄弟元素都只根据索引工作。

例如

<div class="one">...</div>
<div class="two">...</div>
<div class="three">...</div>
<div class="four">...</div>
<div class="five">...</div>
<div class="rest">...</div>
<div class="rest">...</div>
<div class="rest">...</div>
<div class="rest">...</div>
<div class="rest">...</div>

假设在上面的 html 中我们想要隐藏所有具有 rest 类的元素。

在这种情况下,nth-childnth-of-type 的工作方式与所有元素的类型完全相同,即 &lt;div&gt;,因此 css 应该是

.rest:nth-child(6), .rest:nth-child(7), .rest:nth-child(8), .rest:nth-child(9), .rest:nth-child(10)
    display:none;

.rest:nth-of-type(6), .rest:nth-of-type(7), .rest:nth-of-type(8), .rest:nth-of-type(9), .rest:nth-of-type(10)
    display:none;

现在您一定想知道nth-childnth-of-type 之间有什么区别,所以这就是区别

假设html是

<div class="one">...</div>
<div class="two">...</div>
<div class="three">...</div>
<div class="four">...</div>
<div class="five">...</div>
<p class="rest">...</p>
<p class="rest">...</p>
<p class="rest">...</p>
<p class="rest">...</p>
<p class="rest">...</p>

在上面的 html 中,.rest 元素的类型与其他元素不同,.rest 是段落,其他的是 div,所以在这种情况下,如果你使用 nth-child,你必须这样写

.rest:nth-child(6), .rest:nth-child(7), .rest:nth-child(8), .rest:nth-child(9), .rest:nth-child(10)
    display:none;

但如果你使用 nth-of-type css 可以是这样的

.rest:nth-of-type(1), .rest:nth-of-type(2), .rest:nth-of-type(3), .rest:nth-of-type(4), .rest:nth-of-type(5)
    display:none;

由于.rest元素的类型是&lt;p&gt;,所以这里nth-of-type正在检测.rest的类型,然后他在&lt;p&gt;的第1、2、3、4、5个元素上应用了css。

【讨论】:

这对于&lt;tr&gt; 标签有多大用处?【参考方案4】:

你也许可以用 xpath 做到这一点。 //tr[contains(@class, 'row') and position() mod 2 = 0] 之类的东西可能会起作用。还有其他 SO 问题扩展了如何更精确地匹配类的细节。

【讨论】:

【参考方案5】:

这是你的答案

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>TEST</title>

  <style>

    .block 
      background: #fc0;
      margin-bottom: 10px;
      padding: 10px;
    
    /* .large > .large-item:nth-of-type(n+5) 
      background: #f00;
     */

    .large-item ~ .large-item ~ .large-item ~ .large-item ~ .large-item 
      background: #f00;
    

  </style>
</head>
<body>

<h1>Should be the 6th Hello Block that start red</h1>
<div class="small large">
  <div class="block small-item">Hello block 1</div>
  <div class="block small-item large-item">Hello block 2</div>
  <div class="block small-item large-item">Hello block 3</div>
  <div class="block small-item large-item">Hello block 4</div>
  <div class="block small-item large-item">Hello block 5</div>
  <div class="block small-item large-item">Hello block 6</div>
  <div class="block small-item large-item">Hello block 7</div>
  <div class="block small-item large-item">Hello block 8</div>
</div>

</body>
</html>

【讨论】:

【参考方案6】:

所有关于使用 nth-child 和跳过隐藏标签的问题似乎都被重定向为这个问题的傻瓜,所以我将把它留在这里。我偶然发现了这个博客https://blog.blackbam.at/2015/04/09/css-nth-child-selector-ignore-hidden-element/,它使用巧妙的css方法让nth-child忽略隐藏元素,如下:

以下 CSS 为每个可见元素添加一个边距,无论哪个元素具有 cpw 类。

.cpw 
    display:none;


.video_prewrap 
    margin-right:20px;


.video_prewrap:nth-child(2n) 
    margin-right:0;


.cpw ~ .video_prewrap:nth-child(2n) 
    margin-right:20px;


.cpw ~ .video_prewrap:nth-child(2n-1) 
    margin-right:0;

希望能帮助那些追寻忽略隐藏元素问题的人!

【讨论】:

我想对此投赞成票,但它需要一个有效的演示。 我的回忆是,这实际上并不像最初看起来那样强大 - 我现在会选择最高票数的评论,这是不可能的。【参考方案7】:

如果所有选择器的父类都相同,则使用该类document.querySelector("main .box-value:nth-child(3) select.priorityOption"); 因为在那种情况下document.querySelector("main .box-value select.priorityOption:nth-child(3)"); 不工作。谢谢你

<div class="card table">
    <div class="box">
        <div class="box-value">
            <select class="priorityOption">
                <option value="">--</option>
                <option value="">LOREM</option>
                <option value="">LOREM</option>
            </select>
        </div>

        <div class="box-value">
            <select class="priorityOption">
                <option value="">--</option>
                <option value="">LOREM</option>
                <option value="">LOREM</option>
            </select>
        </div>

        <div class="box-value">
            <select class="priorityOption">
                <option value="">--</option>
                <option value="">LOREM</option>
                <option value="">LOREM</option>
            </select>
        </div>
    </div>
</div>

【讨论】:

【参考方案8】:

不是“有人能解释为什么吗?”的答案。因为其他答案已经解释了。

但作为一种可能的解决方案,您可以为行和单元格使用自定义标签,例如&lt;tr-row&gt;&lt;td-row&gt;,然后:nth-of-type() 应该可以工作。不要忘记分别设置样式display: table-row;display: table-cell; 以使它们仍然像表格单元格一样工作。

【讨论】:

以上是关于我可以将 :nth-child() 或 :nth-of-type() 与任意选择器结合使用吗?的主要内容,如果未能解决你的问题,请参考以下文章

利用jquery怎么遍历table中的一列

如何使用 Selenium 的标准 CSS 选择器(nth-of-type 或 nth-child)选择嵌套元素?

CSS3 伪类选择器 :nth-child()

nth-child(n) 选择器

jQuery找到'nth-child'值

CSS3 之:nth-child() 选择器