ChatGPT解决这个技术问题 Extra ChatGPT

具有类的第一个元素的 CSS 选择器

我有一堆类名为 red 的元素,但我似乎无法使用以下 CSS 规则选择带有 class="red" 的第一个元素:

.home .red:first-child { 边框:1px 纯红色; }

blah

first

second

第三个

第四个

这个选择器有什么问题,我该如何纠正它以定位第一个具有 red 类的孩子?


B
BoltClock

这是作者误解 :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 { 边框:无; }

blah

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 APISelenium 的 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)),因为每个元素都是其类型中的第一个(也是唯一一个)(分别为 pdiv),所以 将被选择器匹配。

当某个类的第一个元素也是其类型的第一个元素时,伪类将起作用,但这只是巧合。这种行为在菲利普的回答中得到了证明。当您在该元素之前插入相同类型的元素时,选择器将失败。从问题中提取标记:

<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 元素。


那么,有什么方法可以模拟 :last-of-class 吗?选择类的最后一个元素。
我想知道为什么 article > p ~ article > p 不起作用/产生与 article > p ~ p 相同的效果。
@Gnuey:那是因为组合器是线性的。在评论中解释起来有点困难,但基本上我会说第一个 > p 意味着第二个 p 通过兄弟组合器是同一个 article 的孩子,所以替换第二个 {4 } 与 article 的工作方式类似,以下 > p 从该点向下遍历一个额外的级别。我还有其他几个答案可以更详细地解释它:stackoverflow.com/a/3851754 stackoverflow.com/a/8135729
与兄弟的技术很好。可能值得注意的是,这也适用于多个同级组合器,例如 p~p~p 将选择第三个及以后的项目:jsfiddle.net/zpnnvedm/1
@ElRoBe:这需要假设第一个 p.red 将始终直接跟随跨度。有时,您可能会发现自己无法对标记做出假设,因为它可能会以某些方式发生变化。例如,该 span 可能并不总是存在,第一个 p.red 可能不会直接跟随它,或者同一父级中可能有多个 span + p.red 对,而您只希望第一个受到影响。但是,如果您能够对标记做出这些假设甚至保证,那么这些更简单的解决方案将可供您使用。
M
Mark Amery

顾名思义,: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>

firstthird 将变为红色。

对于您的情况,您可以使用 :nth-of-type 选择器:

.red:nth-of-type(1) { 边框:5px 纯红色; }

blah

first

second

第三个

第四个

归功于 Martyn,他删除了包含这种方法的答案。更多信息,例如 here。请注意,这是一个 CSS 3 选择器,因此并非所有浏览器都能识别它(例如 IE8 或更早版本)。


我读到这里有点困惑。严格来说,.red:nth-of-type(1) 将选择 (a) 是其元素类型的第一个子元素,并且 (b) 具有“red”类的任何元素。因此,如果在示例中,第一个 <p>没有类“红色”,它不会被选中。或者,如果 <span>和第一个 <p>两者都有“红色”类,他们都会被选中。 jsfiddle.net/fvAxn
@David 几个月前所说的是正确的; :nth-of-type() 不是解决此问题的好方法。我提供了一个更可靠的替代答案,作为奖励,它可以在 IE7+ 中运行,这与 :nth-of-type() 不同。
@Dan Mundy::first-of-type 等同于 :nth-of-type(1),所以它当然也有效。由于我的回答中所述的相同原因,它也可能以同样的方式失败。
@David 我确定 :nth-of-type 表示“类型”时表示“元素/标签”。所以它只考虑元素,而不考虑类之类的东西。
@gcampbell:是的,这正是它的意思,这就是为什么这个答案有缺陷。选择“类型”一词的原因是为了不将选择器与 HTML/XML 结合起来,因为并非所有语言都有定义元素的“标签”概念。
K
Kyle

正确答案是:

.red:first-child, :not(.red) + .red { border:5px solid red }

第一部分:如果元素是其父元素的第一个并且具有“red”类,它将获得边框。第二部分:如果“.red”元素不是第一个到它的父元素,而是紧跟在一个没有类“.red”的元素之后,它也应该得到该边框的荣誉。

Fiddle or it didn't happen.

Philip Daubmeier 的回答虽然被接受,但不正确 - 请参阅随附的小提琴。 BoltClock 的答案会起作用,但会不必要地定义和覆盖样式(尤其是它会继承不同边框的问题 - 您不想将 other 声明为边框:none)

编辑:如果您在非红色之后多次出现“红色”,则每个“第一个”红色都会获得边框。为了防止这种情况,需要使用 BoltClock 的答案。请参阅fiddle


这个答案没有错,选择器 is 对于给定的标记是正确的,但我应该重申,编辑中提到的情况是我声明至少在你不能保证时需要覆盖的原因标记结构 - 仅仅因为 .red 跟随 :not(.red) 并不总是使其成为其兄弟姐妹中的第一个 .red。如果需要继承边框,只需在覆盖规则中声明 border: inherit 而不是 border: none 即可。
N
Nerdroid

您可以使用 first-of-typenth-of-type(1)

.red { 颜色:绿色; } /* .red:nth-of-type(1) */ .red:first-of-type { color: red; }

blah

first

second

第三个

第四个


如果您在 span 和您的第一个 p 元素与 red 类之间有一个 <p></p>,它将不起作用。看看这个JSFiddle
G
Gabriel Fair

上面的答案太复杂了。

.class:first-of-type { }

这将选择第一类。 MDN Source

注意:在 2021 年 6 月使用 Chrome 91 和 Firefox 89 进行了测试。


first-type has been renamed to first-of-type
它不适用于类。这就是它应该如何工作的,因为选择一个类的第 n 个比选择一个标签的第 n 个更有用。但是 ':first-of-type' 只对 tagName 起作用。如果“first-of-class”和“first-of-tag”碰巧指的是同一个元素,他们经常这样做,那么很容易让自己误以为它确实以这种方式工作;然后想知道当你遇到他们没有的情况时发生了什么。
@Bernesto,当您遇到多个具有相同“类型”的元素的情况时,可以说<span>,其中一些具有highlight 类。 .highlight:first-of-type 选择器将选择具有所选类的“类型”的第一个实例,在本例中是第一个 <span>,而不是类 highlight 的第一个实例。只有当 span 的第一个实例也具有类 highlight 时,才会实现该样式。 (codepen.io/andrewRmillar/pen/poJKJdJ)
我的答案如此复杂的原因是因为它的最后一部分,以及我对其他几个答案的评论,准确地解释了为什么这是有缺陷的。在事实两年后将指向 MDN 的链接添加到您的答案中,当您没有尝试将 MDN 材料与之关联时,并不能完全支持它 - 大概是因为您做不到。
L
Learning Mathematics

我很惊讶没有人提到最干净的解决方案:

.red:not(.red ~ .red) { 边框:1px 纯红色; }

blah

first

second

第三个

第四个


不是“以 .red 开头的 .red”的 .red。本例中只有第一个。但如果在两者之间插入另一个类,它将不起作用。注意:.red:not(.red ~ *) 也应该可以工作(“a red that is not "anything before a .red")
@hl037_ 为什么它不起作用?你确定你没有弄错'+'和'~'选择器,直接兄弟和任意距离兄弟吗?
如何选择“红色”类的最后一个元素?
B
BoltClock

由于其他答案涵盖了它的问题所在,我将尝试另一半,如何解决它。不幸的是,我不知道你这里有一个纯 CSS 的解决方案,至少我想不到。不过还有一些其他的选择......

生成元素时为其分配第一类,如下所示:

CSS: .first.red {border:5px纯红色;这个 CSS 只匹配具有 first 和 red 类的元素。或者,在 JavaScript 中执行相同的操作,例如,使用与上面相同的 CSS 来执行此操作的 jQuery 如下: $(".red:first").addClass("first");


我想出了一个纯 CSS 的解决方案 a while ago;我在这里复制了它作为规范的答案。
只要没有像 :first-of-class 这样的东西,我还建议在第一个元素中添加一个额外的类。目前似乎是最简单的解决方案。
d
dj.cowan

要匹配您的选择器,该元素的类名必须为 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>

Y
Yener Örer

我在我的项目中得到了这个。

div > .b ~ .b:not(:first-child) { 背景:无; } div > .b { 背景:红色; }

第一段。

第二段。

第三段。

p>

第四段。


在我的回答中应用该技术时,您不需要 :not(:first-child) 。 ~ 组合器意味着 :not(:first-child) 将始终匹配,因此是多余的 - 它对您的选择器真正产生的唯一影响是额外的特异性。而且您不需要这种额外的特异性,因此您可以(并且可能应该)将其省略。
S
StinkyCat

根据您更新的问题

<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


T
TylerH

我正在使用下面的 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);背景重复:不重复; }


T
TylerH

由于某种原因,上述答案似乎都没有解决父母真正的第一个也是唯一的第一个孩子的情况。

#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>

我们的答案没有解决这个问题的原因是因为这不是问题一开始就要求的。这个答案将更好地作为一个单独问题的答案。
P
Prabhakar Undurthi

您可以将代码更改为类似的内容以使其正常工作

<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 参考资料。


J
Jamie Paterson

您可以使用 nth-of-type(1) 但请确保该站点不需要支持 IE7 等,如果是这种情况,请使用 jQuery 添加正文类,然后通过 IE7 正文类查找元素,然后查找元素名称,然后添加在它的第 n 个子样式中。


M
Melchia

总而言之,在阅读了所有页面和其他页面以及大量文档之后。这是摘要:

对于第一个/最后一个孩子:现在可以安全使用(所有现代浏览器都支持)

:nth-child() 现在也可以安全使用(所有现代浏览器都支持)。但要小心它甚至计算兄弟姐妹!因此,以下内容将无法正常工作:

/* 这应该选择类 display_class 的前 2 个元素 * 但它不会工作因为 nth-child 甚至是兄弟姐妹 * 包括第一个 div skip_class */ .display_class:nth-child(-n+2){ background-color :绿色; }

  • test 1
  • test 2 应该是绿色的
  • test 3 应该是绿色的
  • 测试4

目前,有一个 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 { 背景色:绿色; }

  • test 1
  • test 2 应该是绿色的
  • test 3 应该是绿色的
  • 测试4


A
AliAfzali

下面的代码肯定会在任何地方都能正常工作。它简单而简短。

<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,则应使用 + 而不是 ~


F
Friend

试试这个简单有效

 .home > span + .red{
      border:1px solid red;
    }

N
Nesha Zoric

我相信使用相对选择器 + 来选择紧随其后的元素,在这里效果最好(正如之前很少有人建议的那样)。

这种情况也可以使用这个选择器

.home p:first-of-type

但这是元素选择器而不是第一类。

在这里你有一个很好的 CSS 选择器列表:https://kolosek.com/css-selectors/


V
Vitalii Andrusishyn

你可以尝试这样的事情:

.red:first-of-type {
    border: 5px solid red;
}

您也可以将其用于最后一个元素(如果需要):

.red:last-of-type {
    border: 5px solid red;
}

G
Germanjeet Singh

只需使用

.home > .red ~ .red{
 border: 1px solid red;
}

它会起作用的。


不要只说 use thisthis will work 解释它如何以及为什么会起作用。
尤其是在像这样的老问题上,有很多赞成的答案
T
TylerH

试试这个解决方案:

.home p:first-of-type { 边框:5px 纯红色;宽度:100%;显示:块; }

blah

first

second

第三个

第四个

CodePen link


问题是“带有类的第一个元素的 CSS 选择器”,而不是“带有标签名称的第一个元素的 CSS 选择器”。
J
John Conde

我想很多人已经解释过了。您的代码只选择第一个实例的第一个孩子。如果要选择所有红色类的第一个孩子,则需要使用

.home > .red:first-child {
    /* put your styling here */
}