python小菜 2010-04-26 22:51 采纳率: 0%
浏览 2485
已采纳

带 class 的第一个元素的 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:

.red:first-child {
    border: 5px solid red;
}
<p class="red"></p>
<div class="red"></div>

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

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, and this rule fails as mentioned in the comments:

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

How can I target the first child with class red?

</div>

转载于:https://stackoverflow.com/questions/2717480/css-selector-for-first-element-with-class

  • 写回答

15条回答 默认 最新

  • 胖鸭 2011-12-16 19:21
    关注

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

    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.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(14条)

报告相同问题?

悬赏问题

  • ¥50 导入文件到网吧的电脑并且在重启之后不会被恢复
  • ¥15 (希望可以解决问题)ma和mb文件无法正常打开,打开后是空白,但是有正常内存占用,但可以在打开Maya应用程序后打开场景ma和mb格式。
  • ¥20 ML307A在使用AT命令连接EMQX平台的MQTT时被拒绝
  • ¥20 腾讯企业邮箱邮件可以恢复么
  • ¥15 有人知道怎么将自己的迁移策略布到edgecloudsim上使用吗?
  • ¥15 错误 LNK2001 无法解析的外部符号
  • ¥50 安装pyaudiokits失败
  • ¥15 计组这些题应该咋做呀
  • ¥60 更换迈创SOL6M4AE卡的时候,驱动要重新装才能使用,怎么解决?
  • ¥15 让node服务器有自动加载文件的功能