具有类的第一个元素的 CSS 选择器 [英] CSS selector for first element with class

查看:17
本文介绍了具有类的第一个元素的 CSS 选择器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a bunch of elements with a class name red, but I can't seem to select the first element with the class="red" using the following CSS rule:

.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 来定位第一个孩子?

What is wrong in this selector and how do I correct it to target the first child with class red?

推荐答案

这是作者误解 :first-child 工作原理的最著名例子之一.CSS2中引入:first-child 伪类代表其父级的第一个子级.而已.有一个非常常见的误解,即它会选择第一个匹配复合选择器其余部分指定的条件的子元素.由于选择器的工作方式(请参阅 这里解释),这根本不是真的.

This is one of the most well-known examples of authors misunderstanding how :first-child works. Introduced in CSS2, the :first-child pseudo-class represents the very first child of its parent. That's it. There's a very common misconception that it picks up whichever child element is the first to match the conditions specified by the rest of the compound selector. Due to the way selectors work (see here for an explanation), that is simply not true.

选择器级别 3 引入了一个 :first-of-type 伪类,表示其元素类型的兄弟元素中的第一个元素.这个答案用插图解释了 :first-child:first-of-type 之间的区别.但是,与 :first-child 一样,它不查看任何其他条件或属性.在 HTML 中,元素类型由标签名称表示.在问题中,该类型是 p.

Selectors level 3 introduces a :first-of-type pseudo-class, which represents the first element among siblings of its element type. This answer explains, with illustrations, the difference between :first-child and :first-of-type. However, as with :first-child, it does not look at any other conditions or attributes. In HTML, the element type is represented by the tag name. In the question, that type is p.

不幸的是,没有类似的 :first-of-class 伪类来匹配给定类的第一个子元素.在首次发布此答案时,新发布的 FPWD选择器级别 4 引入了一个 :nth-match() 伪类,它围绕我在第一段中提到的现有选择器机制设计,添加了一个选择器列表参数,通过它你可以提供复合选择器的其余部分以获得所需的过滤行为.近年来,此功能被 纳入 :nth-child() 本身,选择器列表显示为可选的第二个参数,以简化事情并避免 :nth-match() 匹配的错误印象整个文档(请参阅下面的最后注释).

Unfortunately, there is no similar :first-of-class pseudo-class for matching the first child element of a given class. At the time this answer was first posted, the newly published FPWD of Selectors level 4 introduced an :nth-match() pseudo-class, designed around existing selector mechanics as I mentioned in the first paragraph by adding a selector-list argument, through which you can supply the rest of the compound selector to get the desired filtering behavior. In recent years this functionality was subsumed into :nth-child() itself, with the selector list appearing as an optional second argument, to simplify things as well as averting the false impression that :nth-match() matched across the entire document (see the final note below).

虽然我们在等待跨浏览器支持(说真的,已经快 10 年了,并且在过去 5 年中只有一个实现),一种解决方法 Lea Verou 和我独立开发(她首先做到了!)是首先将您想要的样式应用于该类的所有元素:

While we await cross-browser support (seriously, it's been nearly 10 years, and there has only been a single implementation for the last 5 of those years), one workaround that Lea Verou and I developed independently (she did it first!) is to first apply your desired styles to all your elements with that class:

/* 
 * Select all .red children of .home, including the first one,
 * and give them a border.
 */
.home > .red {
    border: 1px solid red;
}

...然后撤消"在第一个类之后的元素的样式,使用 覆盖规则中的通用兄弟组合~:

... then "undo" the styles for elements with the class that come after the first one, using the general sibling combinator ~ in an overriding rule:

/* 
 * Select all but the first .red child of .home,
 * and remove the border from the previous rule.
 */
.home > .red ~ .red {
    border: none;
}

现在只有 class="red" 的第一个元素会有边框.

Now only the first element with class="red" will have a border.

以下是如何应用规则的说明:

Here's an illustration of how the rules are applied:

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

.home > .red ~ .red {
    border: none;
}

<div class="home">
  <span>blah</span>         <!-- [1] -->
  <p class="red">first</p>  <!-- [2] -->
  <p class="red">second</p> <!-- [3] -->
  <p class="red">third</p>  <!-- [3] -->
  <p class="red">fourth</p> <!-- [3] -->
</div>

  1. 没有应用任何规则;不渲染边框.
    该元素没有 red 类,因此被跳过.

只应用第一条规则;呈现红色边框.
此元素具有类 red,但其前面没有任何在其父级中具有类 red 的元素.因此不应用第二条规则,只应用第一条规则,并且元素保持其边界.

Only the first rule is applied; a red border is rendered.
This element has the class red, but it's not preceded by any elements with the class red in its parent. Thus the second rule is not applied, only the first, and the element keeps its border.

两个规则都适用;不渲染边框.
该元素具有类 red.它前面还有至少一个具有 red 类的其他元素.因此,两个规则都被应用,并且第二个 border 声明覆盖了第一个,从而撤消"了边界.可以这么说.

Both rules are applied; no border is rendered.
This element has the class red. It is also preceded by at least one other element with the class red. Thus both rules are applied, and the second border declaration overrides the first, thereby "undoing" it, so to speak.

作为奖励,虽然它是在 Selectors 3 中引入的,但与 :first-of-type:nth 不同,IE7 和更新版本实际上很好地支持了通用兄弟组合器-of-type() 只有 IE9 以后才支持.如果您需要良好的浏览器支持,那么您很幸运.

As a bonus, although it was introduced in Selectors 3, the general sibling combinator is actually pretty well-supported by IE7 and newer, unlike :first-of-type and :nth-of-type() which are only supported by IE9 onward. If you need good browser support, you're in luck.

事实上,兄弟组合器是该技术中唯一重要的组件,并且它具有如此惊人的浏览器支持,这使得该技术非常通用 - 您可以通过以下方式将其用于过滤元素除了类选择器之外的其他东西:

In fact, the fact that the sibling combinator is the only important component in this technique, and it has such amazing browser support, makes this technique very versatile — you can adapt it for filtering elements by other things, besides class selectors:

  • 您可以使用它来解决 IE7 和 IE8 中的 :first-of-type,只需提供类型选择器而不是类选择器(同样,更多关于它的不正确用法在后面部分的问题中):

  • You can use this to work around :first-of-type in IE7 and IE8, by simply supplying a type selector instead of a class selector (again, more on its incorrect usage in the question in a later section):

 article > p {
     /* Apply styles to article > p:first-of-type, which may or may not be :first-child */
 }

 article > p ~ p {
     /* Undo the above styles for every subsequent article > p */
 }

  • 您可以按 属性选择器或任何其他简单的选择器而不是类.

  • You can filter by attribute selectors or any other simple selectors instead of classes.

    您还可以将此覆盖技术与 伪元素 尽管伪元素在技术上并不是简单的选择器.

    You can also combine this overriding technique with pseudo-elements even though pseudo-elements technically aren't simple selectors.

    请注意,为了使其正常工作,您需要提前知道其他同级元素的默认样式是什么,以便您可以覆盖第一条规则.此外,由于这涉及覆盖 CSS 中的规则,因此您无法使用单个选择器来实现相同的效果,以便与 选择器 API,或 Selenium 的 CSS 定位器.

    Note that in order for this to work, you will need to know in advance what the default styles will be for your other sibling elements so you can override the first rule. Additionally, since this involves overriding rules in CSS, you can't achieve the same thing with a single selector for use with the Selectors API, or Selenium's CSS locators.

    最后一点,请记住,此答案假定问题正在寻找具有给定类的 任意数量 个第一个子元素.对于复杂选择器的第 n 次匹配整个文档,既没有伪类,也没有通用 CSS 解决方案——解决方案是否存在很大程度上取决于文档结构.为此,jQuery 提供了 :eq():first:last 等,但请再次注意 它们的功能与 :nth-child() et al.使用 Selectors API,您可以使用 document.querySelector() 来获取第一个匹配项:

    On a final note, keep in mind that this answer assumes that the question is looking for any number of first child elements having a given class. There is neither a pseudo-class nor even a generic CSS solution for the nth match of a complex selector across the entire document — whether a solution exists depends heavily on the document structure. jQuery provides :eq(), :first, :last and more for this purpose, but note again that they function very differently from :nth-child() et al. Using the Selectors API, you can either use document.querySelector() to obtain the very first match:

    var first = document.querySelector('.home > .red');
    

    或者使用 document.querySelectorAll() 和索引器来选择任何特定的匹配:

    Or use document.querySelectorAll() with an indexer to pick any specific match:

    var redElements = document.querySelectorAll('.home > .red');
    var first = redElements[0];
    var second = redElements[1];
    // etc
    


    虽然 Philip Daubmeier 作品(最初由 Martyn 但已删除),它的行为与您期望的不同.


    Although the .red:nth-of-type(1) solution in the original accepted answer by Philip Daubmeier works (which was originally written by Martyn but deleted since), it does not behave the way you'd expect it to.

    例如,如果您只想在此处选择 p:

    For example, if you only wanted to select the p here:

    <p class="red"></p>
    <div class="red"></div>
    

    ...那么你就不能使用.red:first-of-type(相当于.red:nth-of-type(1)),因为每个元素都是其类型中的第一个(也是唯一一个)(分别为 pdiv),所以 both 将被选择器匹配.

    ... then you can't use .red:first-of-type (equivalent to .red:nth-of-type(1)), because each element is the first (and only) one of its type (p and div respectively), so both will be matched by the selector.

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

    When the first element of a certain class is also the first of its type, the pseudo-class will work, but this happens only by coincidence. This behavior is demonstrated in Philip's answer. The moment you stick in an element of the same type before this element, the selector will fail. Taking the markup from the question:

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

    Applying a rule with .red:first-of-type will work, but once you add another p without the class:

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

    ... the selector will immediately fail, because the first .red element is now the second p element.

    这篇关于具有类的第一个元素的 CSS 选择器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆