Why can't I override existing pseudo-elements?
Asked Answered
F

3

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?

Feebleminded answered 7/4, 2012 at 15:56 Comment(6)
Will .some td.other:before not work?Caylacaylor
The first has more specificity than the other.Blacken
@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.Feebleminded
@JaredFarrish: why? the 2nd one has two class selectors, the first just one. Shouldn't it use that one instead if it matches?Feebleminded
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.Blacken
@JaredFarrish: You're right. Adding a td before .other does the trick. Need to read up on pseudo-element specificity... Thanks.Feebleminded
F
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.

Feebleminded answered 7/4, 2012 at 16:44 Comment(3)
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?Elude
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!Elude
See What is the difference between a pseudo-class and a pseudo-element in CSS?Advert
L
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.

Lewin answered 7/4, 2012 at 16:11 Comment(2)
Thing is, it's always using the first one, not the 2nd.Feebleminded
@DanMan, Oops, i calculated the specificity and you are right, updated the answer.Lewin
C
2

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

Customer answered 7/4, 2012 at 16:5 Comment(2)
!important is a last resort means, to be used if everything else fails.Elude
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.Malayoindonesian

© 2022 - 2024 — McMap. All rights reserved.