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

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

问题描述

我有一堆类的元素 red

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



我似乎不能选择第一个元素与 class =红色使用以下CSS规则:

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

这个选择器有什么问题, >

UPDATE



感谢评论,我发现元素必须它的父亲的第一个孩子得到选择,这不是我的情况。我有以下结构:

 < div class =home> 
< span> blah< / span>
< p class =red>第一< / p>
< p class =red>第二< / p>
< p class =red>第三< / p>
< p class =red>第四< / p>
< / div>

并且此规则在注释中提及失败:

  .home .red:first-child {
border:1px solid red;
}

如何使用 c>

解决方案

这是最着名的作者之一误解:first-child 工程。 在CSS2中引入:first -child 伪类表示其父类的第一个子。而已。有一个非常普遍的误解,它挑选任何子元素是第一个匹配由复合选择器的其余部分指定的条件。由于选择器的工作方式(请参阅这里了解),这根本不是真的。



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



不幸的是,没有类似的 first-of-class 伪类用于匹配给定类的第一个子元素。 Lea Verou 的一种解决方法,我来了(尽管完全独立)是使用该类对所有元素应用样式:

  / * 
*选择.home的所有.red子项,包括第一个
*,并给它们一个边框。
* /
.home> .red {
border:1px solid red;
}

然后使用在第一个之后,使用一般同胞组合<$ c $

  / * 
*选择除.home的第一个.red子项,
*以外的所有项,并从上一个规则中删除边框。
* /
.home> .red〜.red {
border:none;
}

现在只有第一个元素 class =red



 < div class =home> 
< span> blah< / span> <! - [1] - >
< p class =red>第一< / p> <! - [2] - >
< p class =red>第二< / p> <! - [3] - >
< p class =red>第三< / p> <! - [3] - >
< p class =red>第四< / p> <! - [3] - >
< / div>






  1. 此元素没有类 red ,因此跳过。


  2. 仅应用第一个规则;

    此元素具有 red 类,但不会在任何元素前加上 red


  3. 这两个规则都适用;

    此元素具有 red 类。它之前还有至少一个其他元素类 red 。因此,应用这两个规则,第二个 border 声明覆盖第一个,从而撤消。


作为一个奖励,虽然它是在选择器3中引入的,但是一般的兄弟组合器实际上是由IE7和更新的支持,不像:第一类型:nth-​​of-type(),它们仅由IE9向前支持。



事实上,兄弟组合器是这项技术中唯一重要的组件,它有这样惊人的浏览器支持,使这种技术非常多才多艺 - 你可以适应它过滤元素除了类选择器:





请注意,为了使其工作,您需要提前了解其他同级元素的默认样式,以便您可以覆盖第一个规则。此外,由于这涉及在CSS中覆盖规则,因此使用单个选择器不能实现相同的事情,使用选择器API Selenium 的CSS定位器。



值得一提的是,Selectors 4引入了扩展程序到:nth-​​child()符号(原来是一个全新的伪类名为:nth-​​match()),这将允许你使用像:nth-​​child(1 of .red)代替假设的 .red :first-of-class 。作为一个相对最近的提案,没有足够的可互操作的实现,以便在生产站点中可用。希望这将很快改变。在此期间,我建议的解决方法应该适用于大多数情况。



请记住,此回答假设问题是寻找每个第一个子元素一个给定的类。对于整个文档中的复杂选择器的第n个匹配,既没有伪类,也没有一个通用的CSS解决方案 - 解决方案是否依赖于文档结构。 jQuery提供:eq():第一个:last 为此目的,但请再次注意,他们的功能非常不同于:nth-​​child()。使用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






code> .red:nth-​​of-type(1)解答原始接受的回答 Philip Daubmeier 作品(最初由 Martyn 但从中删除),它的行为方式不符合您的期望。



例如,如果您只想选择 p 在您的原始标记中:

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

那么你不能使用 .red:first-of-type (等价于 .red:nth-​​of-type(1)),因为每个元素是其类型的第一个 p div ),因此 p>

当某个类的第一个元素也是其类型的第一个时,伪类将起作用,但通过巧合。这种行为在菲利普的回答中得到了证明。当你在该元素之前粘贴在同一类型的元素时,选择器将失败。使用更新的标记:

 < div class =home> 
< span> blah< / span>
< p class =red>第一< / p>
< p class =red>第二< / p>
< p class =red>第三< / p>
< p class =red>第四< / p>
< / div>

应用 .red:first-of-type 将工作,但一旦你添加另一个 p 没有类:

 < div class =home> 
< span> blah< / span>
< p> dummy< / p>
< p class =red>第一< / p>
< p class =red>第二< / p>
< p class =red>第三< / p>
< p class =red>第四< / p>
< / div>

选择器会立即失败,因为第一个 .red 元素现在是第二 p 元素。


I have a bunch of elements with a class name red:

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

I can't seem to select the first element with the class="red" using the following CSS rule:

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

What is wrong in this selector and how do I correct it?

UPDATE:

Thanks to the comments, I figured out that the element has to be the first child of its parent to get selected which is not the case that I have. I have the following structure:

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

and this rule fails as mentioned in the comments:

.home .red:first-child{
  border:1px solid red;
}

How can I target the first child with class red?

解决方案

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.

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.

Unfortunately, there is no similar :first-of-class pseudo-class for matching the first child element of a given class. One workaround that Lea Verou and I came up with for this (albeit totally independently) is to apply 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;
}

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

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

<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. No rules are applied; no border is rendered.
    This element does not have the class red, so it's skipped.

  2. 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.

  3. 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.

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:

  • 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 here 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.

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.

It's worth mentioning that Selectors 4 introduces an extension to the :nth-child() notation (originally an entirely new pseudo-class called :nth-match()), which will allow you to use something like :nth-child(1 of .red) in lieu of a hypothetical .red:first-of-class. Being a relatively recent proposal, there aren't enough interoperable implementations for it to be usable in production sites yet. Hopefully this will change soon. In the meantime, the workaround I've suggested should work for most cases.

Keep in mind that this answer assumes that the question is looking for every first child element that has 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');

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


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.

For example, if you only wanted to select the p in your original markup:

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

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

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

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>

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

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

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