我有一堆类名为 red
的元素,但我似乎无法使用以下 CSS 规则选择带有 class="red"
的第一个元素:
.home .red:first-child { 边框:1px 纯红色; }
first
second
第三个
第四个
这个选择器有什么问题,我该如何纠正它以定位第一个具有 red
类的孩子?
这是作者误解 :first-child
工作原理的最著名示例之一。 Introduced in CSS2,:first-child
伪类表示其父级的第一个子级。而已。有一个非常常见的误解,即它会选择第一个匹配复合选择器其余部分指定的条件的子元素。由于选择器的工作方式(参见 here 的解释),这根本不是真的。
Selectors level 3 introduces a :first-of-type
pseudo-class,表示其元素类型的兄弟元素中的第一个元素。 This answer 用插图解释了 :first-child
和 :first-of-type
之间的区别。但是,与 :first-child
一样,它不查看任何其他条件或属性。在 HTML 中,元素类型由标签名称表示。在问题中,该类型是 p
。
不幸的是,没有类似的 :first-of-class
伪类来匹配给定类的第一个子元素。在第一次发布此答案时,the newly published FPWD of Selectors level 4 introduced an :nth-match()
pseudo-class 是围绕现有选择器机制设计的,正如我在第一段中提到的那样,通过添加选择器列表参数,您可以提供复合选择器的其余部分以获得所需的过滤行为.近年来,此功能是 subsumed into :nth-child()
itself,选择器列表显示为可选的第二个参数,以简化事情并避免 :nth-match()
在整个文档中匹配的错误印象(请参阅下面的最后注释)。
在我们等待 cross-browser support 的同时(说真的,已经将近 10 年了,在过去的 5 年里只有一个实现),我和 Lea Verou 独立开发的一种解决方法(她先做了!)是首先将您想要的样式应用于该类的 all 元素:
/*
* Select all .red children of .home, including the first one,
* and give them a border.
*/
.home > .red {
border: 1px solid red;
}
...然后“撤消”具有类在第一个之后的元素的样式,在覆盖规则中使用 the general sibling combinator ~
:
/*
* Select all but the first .red child of .home,
* and remove the border from the previous rule.
*/
.home > .red ~ .red {
border: none;
}
现在只有第一个带有 class="red"
的元素会有边框。
以下是如何应用规则的说明:
.home > .red { 边框:1px 纯红色; } .home > .red ~ .red { 边框:无; }
first
第二
第三
第四个
不适用任何规则;不渲染边框。这个元素没有红色类,所以它被跳过了。只应用第一条规则;呈现红色边框。此元素具有 red 类,但它的父级中没有任何具有 red 类的元素。因此不应用第二条规则,只应用第一条规则,并且元素保持其边界。两条规则都适用;不渲染边框。该元素具有红色类。它前面还有至少一个具有红色类的其他元素。因此,这两个规则都适用,并且第二个边界声明覆盖了第一个,从而“撤消”了它,可以这么说。
作为奖励,虽然它是在 Selectors 3 中引入的,但通用兄弟组合器实际上在 IE7 和更新版本中得到了很好的支持,不像 :first-of-type
和 :nth-of-type()
仅在 IE9 及更高版本中支持。如果您需要良好的浏览器支持,那么您很幸运。
事实上,兄弟组合器是该技术中唯一重要的组件,并且它具有如此惊人的浏览器支持,这使得该技术非常通用 - 除了类选择器之外,您还可以将其用于通过其他东西过滤元素:
您可以使用它来解决 :first-of-type in IE7 和 IE8,只需提供一个类型选择器而不是一个类选择器(同样,在后面的问题中更多关于它的不正确用法):article > p { /* 将样式应用于文章 > p:first-of-type,它可能是也可能不是 :first-child */ } article > p ~ p { /* 为每个后续文章撤消上述样式 > p */ }
您可以按属性选择器或任何其他简单选择器而不是类进行过滤。
即使伪元素在技术上不是简单的选择器,您也可以将这种覆盖技术与伪元素结合使用。
请注意,为了使其工作,您需要提前知道其他兄弟元素的默认样式是什么,以便您可以覆盖第一条规则。此外,由于这涉及覆盖 CSS 中的规则,因此您无法使用与 Selectors API 或 Selenium 的 CSS 定位器一起使用的单个选择器来实现相同的目的。
最后一点,请记住,此答案假定问题正在寻找具有给定类的 任意数量 个第一个子元素。对于复杂选择器的第 n 次匹配整个文档,既没有伪类,也没有通用 CSS 解决方案——解决方案是否存在很大程度上取决于文档结构。 jQuery 为此提供了 :eq()
、:first
、:last
等,但请再次注意 they function very differently from :nth-child()
et al。使用 Selectors API,您可以使用 document.querySelector()
获取第一个匹配项:
var first = document.querySelector('.home > .red');
或将 document.querySelectorAll()
与索引器一起使用以选择任何特定匹配项:
var redElements = document.querySelectorAll('.home > .red');
var first = redElements[0];
var second = redElements[1];
// etc
尽管 Philip Daubmeier 接受的原始答案中的 .red:nth-of-type(1)
解决方案有效(最初由 Martyn 编写,但后来被删除),但它的行为与您期望的不同。
例如,如果您只想在此处选择 p
:
<p class="red"></p>
<div class="red"></div>
...那么您就不能使用 .red:first-of-type
(相当于 .red:nth-of-type(1)
),因为每个元素都是其类型中的第一个(也是唯一一个)(分别为 p
和 div
),所以 将被选择器匹配。
当某个类的第一个元素也是其类型的第一个元素时,伪类将起作用,但这只是巧合。这种行为在菲利普的回答中得到了证明。当您在该元素之前插入相同类型的元素时,选择器将失败。从问题中提取标记:
<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:first-of-type
的规则会起作用,但是一旦您添加另一个没有该类的 p
:
<div class="home">
<span>blah</span>
<p>dummy</p>
<p class="red">first</p>
<p class="red">second</p>
<p class="red">third</p>
<p class="red">fourth</p>
</div>
...选择器将立即失败,因为第一个 .red
元素现在是 second p
元素。
顾名思义,:first-child
选择器旨在选择父标记的第一个子标记。所以这个例子可以工作(刚试了一下here):
<body>
<p class="red">first</p>
<div class="red">second</div>
</body>
但是,如果您将标签嵌套在不同的父标签下,或者如果您的 red
类标签不是父标签下的第一个标签,这将不起作用。
还要注意,这不仅适用于整个文档中的第一个这样的标签,而且每次都有一个新的父级围绕它,比如:
<div>
<p class="red">first</p>
<div class="red">second</div>
</div>
<div>
<p class="red">third</p>
<div class="red">fourth</div>
</div>
first
和 third
将变为红色。
对于您的情况,您可以使用 :nth-of-type
选择器:
.red:nth-of-type(1) { 边框:5px 纯红色; }
first
second
第三个
第四个
归功于 Martyn,他删除了包含这种方法的答案。更多信息,例如 here。请注意,这是一个 CSS 3 选择器,因此并非所有浏览器都能识别它(例如 IE8 或更早版本)。
.red:nth-of-type(1)
将选择 (a) 是其元素类型的第一个子元素,并且 (b) 具有“red”类的任何元素。因此,如果在示例中,第一个 <p>没有类“红色”,它不会被选中。或者,如果 <span>和第一个 <p>两者都有“红色”类,他们都会被选中。 jsfiddle.net/fvAxn
:nth-of-type()
不是解决此问题的好方法。我提供了一个更可靠的替代答案,作为奖励,它可以在 IE7+ 中运行,这与 :nth-of-type()
不同。
:first-of-type
等同于 :nth-of-type(1)
,所以它当然也有效。由于我的回答中所述的相同原因,它也可能以同样的方式失败。
:nth-of-type
表示“类型”时表示“元素/标签”。所以它只考虑元素,而不考虑类之类的东西。
正确答案是:
.red:first-child, :not(.red) + .red { border:5px solid red }
第一部分:如果元素是其父元素的第一个并且具有“red”类,它将获得边框。第二部分:如果“.red”元素不是第一个到它的父元素,而是紧跟在一个没有类“.red”的元素之后,它也应该得到该边框的荣誉。
Philip Daubmeier 的回答虽然被接受,但不正确 - 请参阅随附的小提琴。 BoltClock 的答案会起作用,但会不必要地定义和覆盖样式(尤其是它会继承不同边框的问题 - 您不想将 other 声明为边框:none)
编辑:如果您在非红色之后多次出现“红色”,则每个“第一个”红色都会获得边框。为了防止这种情况,需要使用 BoltClock 的答案。请参阅fiddle
.red
跟随 :not(.red)
并不总是使其成为其兄弟姐妹中的第一个 .red
。如果需要继承边框,只需在覆盖规则中声明 border: inherit
而不是 border: none
即可。
您可以使用 first-of-type
或 nth-of-type(1)
.red { 颜色:绿色; } /* .red:nth-of-type(1) */ .red:first-of-type { color: red; }
first
second
第三个
第四个
上面的答案太复杂了。
.class:first-of-type { }
这将选择第一类。 MDN Source
注意:在 2021 年 6 月使用 Chrome 91 和 Firefox 89 进行了测试。
<span>
,其中一些具有highlight
类。 .highlight:first-of-type
选择器将选择具有所选类的“类型”的第一个实例,在本例中是第一个 <span>
,而不是类 highlight
的第一个实例。只有当 span 的第一个实例也具有类 highlight 时,才会实现该样式。 (codepen.io/andrewRmillar/pen/poJKJdJ)
我很惊讶没有人提到最干净的解决方案:
.red:not(.red ~ .red) { 边框:1px 纯红色; }
first
second
第三个
第四个
.red
开头的 .red
”的 .red
。本例中只有第一个。但如果在两者之间插入另一个类,它将不起作用。注意:.red:not(.red ~ *)
也应该可以工作(“a red
that is not "anything
before a .red
")
由于其他答案涵盖了它的问题所在,我将尝试另一半,如何解决它。不幸的是,我不知道你这里有一个纯 CSS 的解决方案,至少我想不到。不过还有一些其他的选择......
生成元素时为其分配第一类,如下所示:
CSS: .first.red {border:5px纯红色;这个 CSS 只匹配具有 first 和 red 类的元素。或者,在 JavaScript 中执行相同的操作,例如,使用与上面相同的 CSS 来执行此操作的 jQuery 如下: $(".red:first").addClass("first");:first-of-class
这样的东西,我还建议在第一个元素中添加一个额外的类。目前似乎是最简单的解决方案。
要匹配您的选择器,该元素的类名必须为 red
,并且必须是其父元素的第一个子元素。
<div>
<span class="red"></span> <!-- MATCH -->
</div>
<div>
<span>Blah</span>
<p class="red"></p> <!-- NO MATCH -->
</div>
<div>
<span>Blah</span>
<div><p class="red"></p></div> <!-- MATCH -->
</div>
我在我的项目中得到了这个。
div > .b ~ .b:not(:first-child) { 背景:无; } div > .b { 背景:红色; }
第一段。
第二段。
第三段。
p>第四段。
根据您更新的问题
<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>
怎么样
.home span + .red{
border:1px solid red;
}
这将选择 class home,然后是元素 span,最后是紧接在 span 元素之后的所有 .red 元素。
参考:http://www.w3schools.com/cssref/css_selectors.asp
我正在使用下面的 CSS 为列表 ul li 提供背景图像
#footer .module:nth-of-type(1)>.menu>li:nth-of-type(1){ 背景位置:中心;背景图片:网址(http://monagentvoyagessuperprix.j3.voyagesendirect.com/images/stories/images_monagentvoyagessuperprix/layout/icon-home.png);背景重复:不重复; }
由于某种原因,上述答案似乎都没有解决父母真正的第一个也是唯一的第一个孩子的情况。
#element_id > .class_name:first-child
如果您只想将样式应用于此代码中的第一类孩子,则上述所有答案都将失败。
<aside id="element_id">
Content
<div class="class_name">First content that need to be styled</div>
<div class="class_name">
Second content that don't need to be styled
<div>
<div>
<div class="class_name">deep content - no style</div>
<div class="class_name">deep content - no style</div>
<div>
<div class="class_name">deep content - no style</div>
</div>
</div>
</div>
</div>
</aside>
您可以将代码更改为类似的内容以使其正常工作
<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>
这为你做的工作
.home span + .red{
border:3px solid green;
}
这是来自 SnoopCode 的 CSS 参考资料。
您可以使用 nth-of-type(1) 但请确保该站点不需要支持 IE7 等,如果是这种情况,请使用 jQuery 添加正文类,然后通过 IE7 正文类查找元素,然后查找元素名称,然后添加在它的第 n 个子样式中。
总而言之,在阅读了所有页面和其他页面以及大量文档之后。这是摘要:
对于第一个/最后一个孩子:现在可以安全使用(所有现代浏览器都支持)
:nth-child() 现在也可以安全使用(所有现代浏览器都支持)。但要小心它甚至计算兄弟姐妹!因此,以下内容将无法正常工作:
/* 这应该选择类 display_class 的前 2 个元素 * 但它不会工作因为 nth-child 甚至是兄弟姐妹 * 包括第一个 div skip_class */ .display_class:nth-child(-n+2){ background-color :绿色; }
目前,有一个 selector :nth-child(-n+2 of .foo) 支持按类选择,但现代浏览器不支持,因此没有用。
因此,这给我们留下了 Javascript 解决方案(我们将修复上面的示例):
// 在这里,我们将遍历具有目标类的元素 // 并将我们的 classmodifer 添加到仅前 2 个元素! [...document.querySelectorAll('.display_class')].forEach((element,index) => { if (index < 2) element.classList.add('display_class--green'); }); .display_class--green { 背景色:绿色; }
下面的代码肯定会在任何地方都能正常工作。它简单而简短。
<div class="home">
<span>blah</span>
<p class="blue"> first-blue </p>
<p class="blue"> second-blue </p>
<p class="blue"> third-blue </p>
<p class="red"> first-red </p>
<p class="red"> second-red </p>
<p class="red"> third-red </p>
<p class="red"> fourth-red </p>
<p class="pink"> first-pink </p>
<p class="pink"> second-pink </p>
<p class="red"> new-first-red </p>
<p class="red"> new-second-red </p>
</div>
我们可以选择 first-red
:
.home .red:not(.home .red ~ .red) {
background-color: blue;
}
如果您也想选择 new-first-red
,则应使用 +
而不是 ~
。
试试这个简单有效
.home > span + .red{
border:1px solid red;
}
我相信使用相对选择器 +
来选择紧随其后的元素,在这里效果最好(正如之前很少有人建议的那样)。
这种情况也可以使用这个选择器
.home p:first-of-type
但这是元素选择器而不是第一类。
在这里你有一个很好的 CSS 选择器列表:https://kolosek.com/css-selectors/
你可以尝试这样的事情:
.red:first-of-type {
border: 5px solid red;
}
您也可以将其用于最后一个元素(如果需要):
.red:last-of-type {
border: 5px solid red;
}
只需使用
.home > .red ~ .red{
border: 1px solid red;
}
它会起作用的。
use this
或 this will work
解释它如何以及为什么会起作用。
试试这个解决方案:
.home p:first-of-type { 边框:5px 纯红色;宽度:100%;显示:块; }
first
second
第三个
第四个
我想很多人已经解释过了。您的代码只选择第一个实例的第一个孩子。如果要选择所有红色类的第一个孩子,则需要使用
.home > .red:first-child {
/* put your styling here */
}
:last-of-class
吗?选择类的最后一个元素。article > p ~ article > p
不起作用/产生与article > p ~ p
相同的效果。> p
意味着第二个p
通过兄弟组合器是同一个article
的孩子,所以替换第二个 {4 } 与article
的工作方式类似,以下> p
从该点向下遍历一个额外的级别。我还有其他几个答案可以更详细地解释它:stackoverflow.com/a/3851754 stackoverflow.com/a/8135729