8

Can anyone tell me why the second row of my table doesn't get a grey background?

<!DOCTYPE html>
<html>
<head>
<style type="text/css">
.phone td {background:blue; color:white;}
.phone:first-of-type td {background:grey;}
</style>
</head>
<body>
<table>
<tbody>
    <tr class="email"><td>Row</td></tr>
    <tr class="phone"><td>Row</td></tr>
    <tr class="phone"><td>Row</td></tr>
</tbody>
</table>
</body>
</html>
Harry
  • 87,580
  • 25
  • 202
  • 214
John
  • 32,403
  • 80
  • 251
  • 422

2 Answers2

13

The first-of-type selectors work on the tags or elements and not on the classes or ids. So in your case the below selector would style the <td> children of the first element of every type which also happens to have the class='phone'.

.phone:first-of-type td {background:grey;}

In your code none of the elements which are the first of it's type have the class='phone'. The first tr has class='email'.

If your first tr had the class='phone' then the style would get applied as seen in the below snippet.

.phone td {
  background: blue;
  color: white;
}
.phone:first-of-type td {
  background: grey;
}
<table>
  <tr class="email"> <!-- will not be styled because it doesn't have phone class-->
    <td>Row</td>
  </tr>
  <tr class="phone"> <!-- will not be styled either because it is not first tr -->
    <td>Row</td>
  </tr>
  <tr class="phone">
    <td>Row</td>
  </tr>
</table>

<table>
  <tr class="phone"> <!-- will be styled because it is first tr and has phone class-->
    <td>Row</td>
  </tr>
  <tr class="phone">
    <td>Row</td>
  </tr>
  <tr class="phone">
    <td>Row</td>
  </tr>
</table>

For your case, you can try the below CSS. This sets the background of all td whose parent has the class='phone' to grey and then overrides it for all its siblings to blue.

You can use either the adjacent sibling selector or the general sibling selector depending on your choice. General Sibling selector is the best.

Note that the adjacent sibling selector won't work complex cases where you have elements with other classes in between elements with class='phone'.

.phone td {background:grey; color:white;}
.phone ~ .phone td { background: blue;}

.phone td {
  background: grey;
  color: white;
}
.phone ~ .phone td {
  background: blue;
}

/* Adding below just to show the difference between the two selectors */
.phone + .phone td {
  color: gold;
}
<table>
  <tr class="email">
    <td>Row</td>
  </tr>
  <tr class="phone">
    <td>Row</td>
  </tr>
  <tr class="email">
    <td>Row</td>
  </tr>
  <tr class="phone">
    <td>Row</td>
  </tr>
  <tr class="phone">
    <td>Row</td>
  </tr>
  <tr class="phone">
    <td>Row</td>
  </tr>  
</table>
<hr>
<table>
  <tr class="phone">
    <td>Row</td>
  </tr>
  <tr class="email">
    <td>Row</td>
  </tr>
  <tr class="phone">
    <td>Row</td>
  </tr>
  <tr class="phone">
    <td>Row</td>
  </tr>
</table>
TylerH
  • 20,799
  • 66
  • 75
  • 101
Harry
  • 87,580
  • 25
  • 202
  • 214
  • Thank you for reply Harry. Can you help me if we consider your own snippet above. In that I would like to trace for second Phone in second table. – Gaurav Lad Jan 12 '16 at 11:59
  • @GauravLad: For the snippet in answer, you can find the method to style only the second phone element in [this demo](https://jsfiddle.net/s2es1pyh/). Hope it helps you :) – Harry Jan 12 '16 at 12:12
1

:first-of-type looks for elements (in the siblings list), not complex selectors. Here, neither of your .phone elements are the first sibling -- .email is.

As far as i know, there is no way to do this in pure CSS without changing your HTML layout.

Scimonster
  • 32,893
  • 9
  • 77
  • 89