我有一堆类名为 red
的元素,但我似乎无法使用以下 CSS 规则选择带有 class="red"
的第一个元素:
.home .red:first-child {
border: 1px solid red;
}
<div class="home">
<span>blah</span>
<p class="red">first</p>
<p class="red">second</p>
<p class="red">third</p>
<p class="red">fourth</p>
</div>
这个选择器有什么问题,我该如何纠正它以针对第一个具有 red
类的孩子?
原文由 Rajat 发布,翻译遵循 CC BY-SA 4.0 许可协议
这是作者误解
:first-child
工作原理的最著名例子之一。 在 CSS2 中引入 的:first-child
伪类代表 其父级的第一个子 级。而已。有一个非常常见的误解,即它会选择第一个匹配复合选择器其余部分指定的条件的子元素。由于选择器的工作方式(请参阅 此处 以获取解释),这根本不是真的。选择器级别 3 引入了一个
:first-of-type
伪类,它表示其元素类型的兄弟元素中的第一个元素。 这个答案 用插图解释了:first-child
和:first-of-type
之间的区别。但是,与:first-child
一样,它不会查看任何其他条件或属性。在 HTML 中,元素类型由标签名称表示。在问题中,该类型是p
。不幸的是,没有类似的
:first-of-class
用于匹配给定类的第一个子元素的伪类。在首次发布此答案时, 新发布的 FPWD 选择器级别 4 引入了:nth-match()
伪类,围绕现有选择器机制设计,正如我在第一段中提到的那样,通过添加选择器列表参数,通过它您可以提供复合选择器的其余部分以获得所需的过滤行为。近年来,此功能被 归入:nth-child()
本身,选择器列表作为可选的第二个参数出现,以简化事情并避免:nth-match()
匹配整个文件(见下面的最后说明)。当我们等待 跨浏览器支持 时(说真的,已经将近 10 年了,在过去的 5 年中只有一个实现), Lea Verou 和我独立开发的一种解决方法(她首先做到了!)是首先将您想要的样式应用于该类的 所有 元素:
…然后“撤消”具有 第一个之后 的类的元素的样式,使用 通用兄弟组合
~
在覆盖规则中:现在只有第一个带有
class="red"
的元素会有边框。以下是如何应用规则的说明:
这个元素没有类
red
,所以它被跳过了。此元素具有类
red
,但它的父级中没有任何具有类red
的元素。因此不应用第二条规则,只应用第一条规则,并且元素保持其边界。该元素具有类
red
。它前面还有至少一个其他元素,其类为red
。因此,这两个规则都适用,第二个border
声明覆盖第一个,从而“撤消”它,可以这么说。作为奖励,虽然它是在选择器 3 中引入的,但通用兄弟组合器实际上得到了 IE7 和更高版本的良好支持,不像
:first-of-type
和:nth-of-type()
仅受 IE9 支持.如果您需要良好的浏览器支持,那么您很幸运。事实上,兄弟组合器是该技术中唯一重要的组件, 并且 它具有如此惊人的浏览器支持,这使得该技术非常通用——除了类选择器之外,您还可以将其用于通过其他东西过滤元素:
:first-of-type
在 IE7 和 IE8 中,只需提供类型选择器而不是类选择器(同样,在后面部分的问题中更多关于它的不正确用法):您可以按 属性选择器 或任何其他简单选择器而不是类进行过滤。
即使伪元素在技术上不是简单的选择器,您也可以将这种覆盖技术与 伪元素 结合使用。
请注意,为了使其工作,您需要提前知道其他兄弟元素的默认样式是什么,以便您可以覆盖第一条规则。此外,由于这涉及覆盖 CSS 中的规则,因此您无法使用与 Selectors API 或 Selenium 的 CSS 定位器一起使用的单个选择器来实现相同的目标。
最后一点,请记住,此答案假定问题正在寻找具有给定类的 任意数量的 第一个子元素。 对于整个文档 中复杂选择器的第 n 次匹配,既没有伪类,也没有通用 CSS 解决方案——解决方案是否存在很大程度上取决于文档结构。 jQuery provides
:eq()
,:first
,:last
and more for this purpose, but note again that they function very differently from:nth-child()
et al .使用 Selectors API,您可以使用document.querySelector()
来获得第一个匹配项:或者使用
document.querySelectorAll()
和索引器来选择任何特定的匹配:尽管
.red:nth-of-type(1)
Philip Daubmeier 工作的原始接受答案中的解决方案(最初由 Martyn 编写,但此后被删除),但它的行为方式并不符合您的预期。例如,如果您只想在此处选择
p
:…那么您不能使用
.red:first-of-type
(相当于.red:nth-of-type(1)
),因为每个元素都是其类型中的第一个(也是唯一一个)一个(p
和div
),所以 两者都 将被选择器匹配。当某个类的第一个元素 也是其类型的 第一个元素时,伪类将起作用,但这 只是巧合。这种行为在菲利普的回答中得到了证明。当您在该元素之前插入相同类型的元素时,选择器将失败。从问题中提取标记:
使用
.red:first-of-type
应用规则将起作用,但是一旦添加另一个p
没有类:…选择器将立即失败,因为第一个
.red
元素现在是 第二个p
元素。