Categories
css css-selectors

CSS selector for first element with class

1212

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>

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

0

    1753

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

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

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

    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.

    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');
    

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

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

    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.

    6

    • 30

      So, is there any way to emulate :last-of-class? Select the last element of a class.

      – gen_Eric

      May 4, 2012 at 22:08

    • I wonder why article > p ~ article > p doesn’t work/produce the same effect as article > p ~ p.

      Aug 29, 2014 at 23:55


    • 1

      @Gnuey: That’s because combinators are linear. It’s a little hard to explain in a comment, but basically I’d say the first > p implies that the second p is a child of the same article by way of the sibling combinator, so replacing that second p with article works similarly, and the following > p traverses one additional level down from that point. I have a couple of other answers that explain it in much greater detail: stackoverflow.com/a/3851754 stackoverflow.com/a/8135729

      – BoltClock

      Aug 30, 2014 at 4:01


    • 4

      Nice technique with the sibling. It might be worth noting this works with multiple sibling combinators as well, e.g. p~p~p will select the third item and beyond: jsfiddle.net/zpnnvedm/1

      – Legolas

      Apr 15, 2015 at 13:53

    • 1

      @ElRoBe: That requires making the assumption that the first p.red will always directly follow a span. Sometimes, you may find yourself unable to make assumptions about the markup because it can vary in certain ways. For example, that span may not always be there, the first p.red may not directly follow it, or there may be more than one span + p.red pair in the same parent and you only want the very first to be affected. But if you are able to make these assumptions or even guarantees about the markup, then these simpler solutions will be available to you.

      – BoltClock

      Mar 5, 2019 at 16:50


    378

    The :first-child selector is intended, like the name says, to select the first child of a parent tag. So this example will work (Just tried it here):

    <body>
        <p class="red">first</p>
        <div class="red">second</div>
    </body>
    

    This won’t work, though, if you’ve nested your tags under different parent tags, or if your tags of class red aren’t the first tags under the parent.

    Notice also that this doesn’t only apply to the first such tag in the whole document, but every time a new parent is wrapped around it, like:

    <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 and third will be red then.

    For your case, you can use the :nth-of-type selector:

    .red:nth-of-type(1)
    {
        border:5px 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>

    Credits to Martyn, who deleted his answer containing this approach. More infos for example here. Be aware that this is a CSS 3 selector, therefore not all browsers will recognize it (e.g. IE8 or older).

    9

    • 28

      I got a bit confused reading this. Strictly .red:nth-of-type(1) will select any element which (a) is the first child of its element type, and (b) has the class “red”. So if, in the example, the the first <p> did not have class “red”, it would not be selected. Alternatively if the <span> and the first <p> both had class “red”, they’d both be selected. jsfiddle.net/fvAxn

      – David

      Oct 12, 2011 at 22:51

    • 1

      What @David said a couple months back is correct; :nth-of-type() is not a good solution to this. I have provided an alternative answer that should be more reliable and, as a bonus, works in IE7+, unlike :nth-of-type().

      – BoltClock

      Dec 16, 2011 at 19:32


    • 7

      @Dan Mundy: :first-of-type is equivalent to :nth-of-type(1), so of course it works, too. It can also fail, too, in the same way for the same reason stated in my answer.

      – BoltClock

      Feb 13, 2013 at 20:19


    • 5

      @David I’m sure :nth-of-type means “element/tag” when it says “type”. So it only considers the element, not things like classes.

      – gcampbell

      Jun 29, 2016 at 17:42

    • 4

      @gcampbell: Yes, that’s exactly what it means, and it’s why this answer is flawed. The reason the word “type” was chosen is so as not to couple Selectors with HTML/XML, since not all languages have a concept of “tags” that define elements.

      – BoltClock

      Jul 6, 2017 at 3:29

    91

    The correct answer is:

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

    Part I: If element is first to its parent and has class “red”, it shall get border.
    Part II: If “.red” element is not first to its parent, but is immediately following an element without class “.red”, it shall also deserve the honor of said border.

    Fiddle or it didn’t happen.

    Philip Daubmeier’s answer, while accepted, is not correct – see attached fiddle.
    BoltClock’s answer would work, but unnecessarily defines and overwrites styles
    (particularly an issue where it otherwise would inherit a different border – you don’t want to declare other to border:none)

    EDIT:
    In the event that you have “red” following non-red several times, each “first” red will get the border. To prevent that, one would need to use BoltClock’s answer. See fiddle

    1

    • 3

      This answer is not wrong, the selector is correct for the given markup, but I should reiterate that the situation mentioned in the edit is the reason why I state that an override is necessary at least when you cannot guarantee the markup structure – just because a .red follows a :not(.red) doesn’t always make it the first .red among its siblings. And if the border needs to be inherited, it’s simply a matter of declaring border: inherit instead of border: none in the override rule.

      – BoltClock

      Feb 26, 2013 at 17:08