Thursday, 14 December 2017

CSS selector for first element with class

itemprop="text">


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:



data-hide="false" data-console="true" data-babel="false">
class="snippet-code">
.red:first-child {
border: 5px solid
red;
}

            class="red">


class="red">






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:



data-hide="false" data-console="true" data-babel="false">
class="snippet-code">
.home .red:first-child {


border: 1px solid red;
}

class="snippet-code-html lang-html prettyprint-override"> class="home">
blah
class="red">first


class="red">second


class="red">third


class="red">fourth








How
can I target the first child with class
red?


itemprop="text">
class="normal">Answer



This is
one of the most well-known examples of authors misunderstanding how
:first-child works. href="http://www.w3.org/TR/CSS21/selector.html#first-child"
rel="noreferrer">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 href="https://stackoverflow.com/questions/5545649/can-i-combine-nth-child-or-nth-of-type-with-an-arbitrary-selector/5546296#5546296">here
for an explanation), that is simply not
true.



href="http://www.w3.org/TR/css3-selectors/#first-of-type-pseudo"
rel="noreferrer">Selectors level 3 introduces a
:first-of-type pseudo-class, which represents the
first element among siblings of its element type. href="https://stackoverflow.com/questions/24657555/what-is-the-difference-between-first-child-and-first-of-type/24657721#24657721">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 href="https://stackoverflow.com/questions/5287272/css-select-first-element-with-a-certain-class/5293095#5293095">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 href="http://www.w3.org/TR/selectors/#general-sibling-combinators"
rel="noreferrer">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:





blah
class="red">first


class="red">second


class="red">third



class="red">fourth






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



    class="lang-css prettyprint-override">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 href="https://stackoverflow.com/questions/7128406/css-select-the-first-child-from-elements-with-particular-attribute/7128429#7128429">attribute
    selectors or any other simple selectors instead of
    classes.


  • You can also combine this
    overriding technique with href="https://stackoverflow.com/questions/8535686/first-child-not-working/8535800#8535800">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 href="http://www.w3.org/TR/selectors-api" rel="noreferrer">Selectors API,
or Selenium's CSS
locators.




It's worth mentioning that
Selectors 4 introduces href="http://dev.w3.org/csswg/selectors-4/#the-nth-child-pseudo" rel="noreferrer">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 href="https://stackoverflow.com/questions/9983297/difference-between-css-selector-and-jquery-filter/10835694#10835694">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
href="https://stackoverflow.com/questions/2717480/css-selector-for-first-element-with-class/2717515#2717515">Philip
Daubmeier works (which was originally written by href="https://stackoverflow.com/users/264276/martyn">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:




class="red">



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






blah

first



second


class="red">third


class="red">fourth





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






blah

dummy


class="red">first


class="red">second


class="red">third


class="red">fourth






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


No comments:

Post a Comment

php - file_get_contents shows unexpected output while reading a file

I want to output an inline jpg image as a base64 encoded string, however when I do this : $contents = file_get_contents($filename); print &q...