9

I have two CSS rules following each other:

.some td:first-child:before {
    content:url('path/to/image.png')" " ;
}
.some .other:before {
    content:url('path/to/image2.png')" " ;
}

Here's the HTML snippet:

<table class="some">
<tr>
    <td class="other">Text goes here</td>
    <td>Some more text.</td>
</tr>
</table>

They're both supposed to be applied to the same table cell. The one without the class is meant as a fallback. But for some reason, it's always choosing the first rule over the second. I know the 2nd one works, since it will be used if i disable the first one in Firebug.

What am I missing here?

DanMan
  • 11,323
  • 4
  • 40
  • 61
  • Will `.some td.other:before` not work? – John H Apr 07 '12 at 16:02
  • 2
    The first has [more specificity](http://www.htmldog.com/guides/cssadvanced/specificity/) than the other. – Jared Farrish Apr 07 '12 at 16:05
  • @JohnH: problem with that is, that "other" will be different, and the fallback rule is supposed to take over, if there's no explicit rule for a specific class. – DanMan Apr 07 '12 at 16:06
  • @JaredFarrish: why? the 2nd one has two class selectors, the first just one. Shouldn't it use that one instead if it matches? – DanMan Apr 07 '12 at 16:07
  • 3
    The first appears to be 31 (three second-level selectors plus an element selector), the second 30 (three second-level selectors, no element selector). Look at how to [calculate your selector specificity](http://css-tricks.com/specifics-on-css-specificity/). – Jared Farrish Apr 07 '12 at 16:11
  • @JaredFarrish: You're right. Adding a `td` before `.other` does the trick. Need to read up on pseudo-element specificity... Thanks. – DanMan Apr 07 '12 at 16:15

3 Answers3

15

Ok, to put this straight, after some reading, this is the specificity:

  • Id: 100
  • classes: 10
  • pseudo-classes: 10
  • pseudo-elements: 1
  • elements: 1

So that makes the first selector have a specificity of 22, and the 2nd of just 21. Apparently first-child seems to be a pseudo-class and not a pseudo-element.

Finally, adding a td before .other does the trick, since then document order takes precedence.

Starx
  • 77,474
  • 47
  • 185
  • 261
DanMan
  • 11,323
  • 4
  • 40
  • 61
  • That's right, yes, a pseudo class is just like a class (in this case, a class name that would be assigned to all first elements) while a pseudo element is a new element in the DOM, in this case one that would be inserted before the element in question. Does that make sense? – Mr Lister Apr 07 '12 at 17:05
  • One could argue all one likes, but no, a class is not an element. Just like in your example, `some` is not an element, only the table with `class="some"` is. Even if you change the class name so it sounds like an element, `class="theThirdTable"`, it's still not an element! – Mr Lister Apr 07 '12 at 17:30
  • 1
    See [What is the difference between a pseudo-class and a pseudo-element in CSS?](http://stackoverflow.com/questions/8069973/what-is-the-difference-between-a-pseudo-class-and-a-pseudo-element-in-css) – BoltClock Apr 24 '12 at 16:37
3

The first rule is more specific than the second one, so in a case when both the selectors are valid, the more specific one overrides other.

Read this article to know how can we overcome such complications of having conflicting styles. To brief them, Here is how specificity are calculated.

+--------------------+--------------------+-----------------------------------+
|    Type            |   Specific Value   |  Example                          |
+--------------------+--------------------+-----------------------------------+
|  Inline Style      |   1000             | style="color: #f00;"              |
+--------------------+--------------------+-----------------------------------+
|  Id                |   100              | #text { color: #f00; }            |
+--------------------+--------------------+-----------------------------------+
|  Classes           |   10               | .text { color: #f00; }            |
+--------------------+--------------------+-----------------------------------+
|  Pseudo Classes    |   10               | a:hover { color: #f00; }          |
+--------------------+--------------------+-----------------------------------+
|  Pseudo Elements   |   10               | a:first-child { color: #f00; }    |
+--------------------+--------------------+-----------------------------------+
|  Elements (tag)    |   1                | a { color: #f00; }                |
+--------------------+--------------------+-----------------------------------+

Basically, Class Selectors are more specific than tag selectors. Lets calculate your specificity

  • For first rule: 31
  • For second rule: 30

SO the first rule wins.

You can increase the specificity of the second rule like

.some tr td.other:before {
    content:url('path/to/image2.png') ;
}

Its calculate to 33, to override the style first rule.

Starx
  • 77,474
  • 47
  • 185
  • 261
2

I'm pretty sure it's to do with the specificity. Try adding !important to the second rule and see if that works.

Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
  • 5
    `!important` is a last resort means, to be used if everything else fails. – Mr Lister Apr 07 '12 at 17:06
  • 2
    Agree on the caveat. But in this case, it's a decent suggestion to quickly see if it can be overriden, answering whether or not it has to do with specificity without having to pin down exactly why. – Patrick M Apr 22 '13 at 17:09