4

I have recently been trying to get my head around why this is not working. Ive started pulling my hair out trying to find a nice solution to a simple problem but every way that I can find to do this just seems messy. Basically what I would like to do is apply some styling to the first child with a specific class within a parent, in my example I am trying to apply a background color of red to the first instance of .class within each .parent. You can see my attempts in the fiddle here.

Here is the final code that I created that is working. The problem is that this seems very messy and I really dont like the fact that I have to set all of the .child classes to red then set all but the first back to white. There must be a cleaner/better way to do this?

HTML

<div class="parent">
    <p>Paragraph</p>
    <div class="child">Child 1</div>
    <div class="child">Child 2</div>
    <div class="child">Child 3</div>
    <div class="child">Child 4</div>
</div>

<div class="parent">
    <p>Paragraph</p>
    <div>Broken</div>
    <div class="child">Child 1</div>
    <div class="child">Child 2</div>
    <div class="child">Child 3</div>
    <div class="child">Child 4</div>
</div>

CSS

/*** Does Not Work ***/
.child:first-child{
    background-color:#f00;
}

/*** Does Not Work ***/
.child:nth-of-type(1){
    background-color:#f00;
}

/*** Works But Is Messy! ***/
.child{
    background-color:#f00;
}
.child ~ .child{
    background-color:#fff;
}
Glen Robson
  • 908
  • 2
  • 19
  • 42
  • I know there is no nth-of-class selector but surely there is a better solution to the one I have above? – Glen Robson Jun 18 '15 at 09:40
  • Hmmmm: http://jsfiddle.net/2cmrko94/6/ – lharby Jun 18 '15 at 14:01
  • More info here: http://stackoverflow.com/a/3615559/1238244 – lharby Jun 18 '15 at 14:09
  • 1
    If there was, I would likely have documented it [here](http://stackoverflow.com/questions/2717480/css-selector-for-first-element-with-class/8539107#8539107), rather than the technique you're currently using. – BoltClock Jun 18 '15 at 14:54
  • Excellent work @BoltClock I also wondered whether this merited a js/jquery response. Something like $('.parent .child:gt(0)'); – lharby Jun 18 '15 at 15:05
  • @lharby: Based on the qSA workaround in the linked answer the equivalent jQuery would be `$('.parent > .child:eq(0)')` (the OP wants to target only the first in this case - the `~ .child` rule is for removing the styles intended for the first). – BoltClock Jun 18 '15 at 15:07

4 Answers4

4

It's probably a bit much but you coud use :not and a universal selector * like so:

*:not(.child) + .child {
  color: red;
}
<div class="parent">
  <p>Paragraph</p>
  <div class="child">Child 1</div>
  <div class="child">Child 2</div>
  <div class="child">Child 3</div>
  <div class="child">Child 4</div>
</div>

<div class="parent">
  <p>Paragraph</p>
  <div>Broken</div>
  <div class="child">Child 1</div>
  <div class="child">Child 2</div>
  <div class="child">Child 3</div>
  <div class="child">Child 4</div>
</div>

Note: However, any break in the sequence (another non-child classed div followed by another child classed div) would repeat the selector.

JSfiddle Demo

Paulie_D
  • 107,962
  • 13
  • 142
  • 161
  • This looks like a better solution than the one I currently have but it is still not perfect. Seems strange that there is no easy or clean way of doing this, plus like you say if you add another non-child classed div followed by another child classed div it would cause problems. – Glen Robson Jun 18 '15 at 09:59
0

May be something like this:

.parent .child:nth-last-child(4) {
    background-color: #f00;
}

Demo

Johnny Juarez
  • 248
  • 6
  • 18
0

If you don't mind changing your HTML markup, a solution would be:

<div class="parent">
  <p>Paragraph</p>
  <div>Broken</div>
  <div class="children">
    <div class="child">Child 1</div>
    <div class="child">Child 2</div>
    <div class="child">Child 3</div>
    <div class="child">Child 4</div>
  </div>
</div>

And:

.child:first-child{
    background-color:#f00;
}

See this fiddle.

Eric MORAND
  • 6,373
  • 4
  • 27
  • 34
-1

I find ':first-of-type' works well for this kind of stuff:

#parent .child:first-of-type {
  background: red;
}

You can also use the same for the last one if needs be:

#parent .child:last-of-type {
  background: red;
}
Tom Durkin
  • 71
  • 9
  • If you try this in the fiddle I have provided it does not work. I have actually already tried this in my fiddle but using an alternative (.child:nth-of-type(1)). This breaks if there is another div above the .child divs. – Glen Robson Jun 18 '15 at 10:01
  • I see. The cleanest solution I can think of still using '**first-of-type**' is to wrap your child divs inside another div, allowing you to have other content inside the parent - [http://codepen.io/tomdurkin/pen/xGXwOG](http://codepen.io/tomdurkin/pen/xGXwOG) – Tom Durkin Jun 18 '15 at 11:27
  • I would have expected this not to work. .child {background:red;} .child:first-of-type {background:yellow;} BUT I would have expected THIS to work .parent .child {background:red;} .parent .child:first-of-type {background:yellow}. It seems as if the parent selector gets ignored? – lharby Jun 18 '15 at 12:30
  • I agree. I tried it but it seems to take no notice of the parent. The only option when using 'first-of-type' seems to be wrapping them in their own div. – Tom Durkin Jun 18 '15 at 14:17
  • 1
    @lharby: Since every element (except the root) has exactly one parent, nth-child and nth-of-type will function consistently on any child element - match if it is the nth child (or nth of its type among its siblings) of its own parent, without you having to specify its parent. That said you *can* specify its parent using the child combinator, rather than the descendant combinator: `.parent > .child:first-child` will only match if `.child` is the first child *and* its parent is `.parent`. – BoltClock Jun 18 '15 at 14:53