Conundrum

I was going to PM Paul directly, but I thought someone else might run into this situation and benefit from the answer. OK, I’ve got the following html (quick sample for this purpose)


[COLOR=#000000]<div id="advertiser">
    <div id="centerContentContainer">
        <table id="edit_listing">
            <tr>
                <td><ul id="allSteps"><li>step1</li><li>step2</li><li>step3</li></ul></td>
            </tr>
            <tr>
                <td><ul id="checklist"><li>check1</li><li>check2</li><li>check3</li></ul></td>
            </tr>
        </table>
    </div>
</div>[/COLOR]

In this case, why does this css


#advertiser #centerContentContainer #edit_listing td ul { margin-left: 10px; }

override this css


#allSteps { margin-left: 0 }

[COLOR=#000000]
Logically (at least to me), the more specific #allSteps should override the drilldown to the generic UL, but it doesn’t work like that in any browser I’ve tried it in.

The reason I’m asking is our organization is starting to make heavy use of LESS and I need to be armed with very specific warnings to pass around so I don’t end up doing a lot of cleanup afterwards (which seems to be my job lately)
[/COLOR]

As Paul is not on-line at present, and I was reading about specificity last night, I’ll hazard an answer and hope it’s right. :slight_smile:

As I understand it, the first rule wins out because it consists of three id selectors - #advertiser, #centerContentContainer and #edit_listing (plus two element selectors td and ul) - whereas the second one only has one id selector - #allSteps.

I agree that the second one seems more specific to a human, but apparently it isn’t to a CSS parser. Three id selectors win out over one, because there are more specifics in the string (i.e. three of them). I’m not sure I’ve explained that too well. (:

Inline styles are considered more specific than anything else, followed by id selectors, then class selectors, then element selectors. If two rules both have the same type of selector, then the one with more instances of that type will win out.

I think that’s right. No doubt Paul will correct me if it isn’t. :slight_smile:

I’m coming to learn that, though from a conceptual standpoint, I’m still having a hard time grasping why. If a specific element (ID) can be applied, then it should override a cascading style (i.e. styles which match generically per a parent relationship).

A co-worker linked me to this page which explains the same thing in an entertaining way (yes, I’m a geek like that)

I agree, but I’m also coming to learn that you can’t make a computer see sense by arguing with it. :headbang:

Brilliant. The book I was reading has that same link, but when I tried it yesterday, I got a 404. I assumed, as the book is a couple of years old, that the page no longer exists. Thank you - I’m off for a read.

Too true - too often, I’m expecting it to do what I want it to do instead of what I tell it to do. This time I’m trying to get it to do what I tell it to do (which for once is the same thing)

Adaptive Web Design? That’s the book my co-worker pulled it from…

[ot]I’ve seen this name before: http://www.stuffandnonsense.co.uk/archives/css_specificity_wars.html#comment48 :wink:
Yes, the Star Wars theme most captivating.[/ot]

Sorry, I’m late to the party but I think you covered most bases however I will explain also :slight_smile: As an aside you should read my entry in the reference as I go into great detail on this subject :slight_smile: (I often have to re-read it myself)

I think you are misconstruing the meaning of specificity in css terms and an element is not more specific if the id is closer to it. When IDs have the same weight and specificity then those later in the in the stylesheet will win out - it makes no difference where the ids/classes are in the html.

e.g.


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Untitled Document</title>
<style type="text/css">
#test2 p{background:blue}
#test p{background:red}

</style>
</head>

<body id="test">
<div id="test2"><p>Test</p></div>
</body>
</html>

In the above CSS both rules have the same weight but the rule that comes later in the stylesheet will win out. It doesn’t matter that #test2 is closer to the element concerned as this has no bearing on the outcome. If the ids were html order dependent then that would destroy the separation between presentation and content in some respects as you would lose control from the stylesheet.

Reverse the css order above but don’t change the html and you will see that the background colour will change.

A co-worker linked me to this page which explains the same thing in an entertaining way (yes, I’m a geek like that)

I saw that years ago and although its a good stab at making it easier to digest I think it actually confuses the issue more and is also inaccurate as Eric Meyer point out.

The easiest way to understand is as shown in my table 6 example here and from the main rules below.

Here’s a simplified description of the process by which the specificity of the selectors of two or more declarations is compared:

  1. If one declaration is from a style attribute, rather than a rule with a selector (an inline style), it has the highest specificity. If none of the declarations are inline, proceed to step two.

  2. Count the ID selectors. The declaration with the highest count has the highest specificity. If two or more have the same number of ID selectors, or they all have zero ID selectors, proceed to step three.

  3. Count the class selectors (for example, .test), attribute selectors (for example, [type=“submit”]), and pseudo-classes (for example, :hover). The declaration with the highest total has the highest specificity. If two or more have the same total, or they all have totals of zero, proceed to step four.

  4. Count the element type selectors (for example div) and pseudo-elements (for example, :first-letter). The declaration with the highest total has the highest specificity.

If two or more selectors have the same specificity, then, according to the rules of the CSS cascade, the latter specified rule takes precedence.

So you can see that the more ids (classes/selectors) you add to your list the more weight the rule has and other rules have to be at least equal (and follow later in the stylesheet) or have even more weight to win out.

As ids are unique there is seldom a need to have more than one id in a rule and generally the only time you would have two ids is if you are trying to be more specific.

Actually, I did read that - I still didn’t understand why my problem was occurring.

Perhaps I am, but in the case I’m citing, the id wasn’t closer, it was on the element itself. That’s why I was confused as to why that style didn’t have more weight than the ul style.

Take your example, Paul. I’ve added a test3 to your html, and tweaked your css. I would expect to see the red background because it’s on the element itself, but it’s blue.


<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Untitled Document</title>
<style type="text/css">
    #test #test2 p{background:blue}
    #test3{background:red}
</style>
</head>
<body id="test">
    <div id="test2">
        <p id="test3">Test</p>
    </div>
</body>
</html>

Agreed - it’s one of the pitfalls of using LESS - you have to be MUCH more diligent on how you place your styles to ensure you don’t end up with more specificity (did you ever try to say that word?) than you intended to…

As I said it doesn’t matter if the id is closer or even on the element itself because rules with more weight will always win out. In your example even “#test p” would win out over #test3. A rule that is specific to an element can be far way in the html or as close as you like. The one with the most weight always wins out. Every time you add something to the rule you are adding more weight based on the tables I linked to above.

That’s all you really need to know about it. If the path is longer and they are both using ids then the longer path wins out. If there is a mixture of ids classes and selectors then you need to refer to the table above and work out which is the heaviest. For example if one has 1 id only and the other on has 500 classes the the rule with all the classes will never win out because ids carry more weight than any number of classes. If both have classes only then the the one with the most classes wins out and so on for type selectors. Or a mixture of all the above. (Ignoring user styles with important and normal rules with important as they have special rules also.)

Therefore you can look at a stylesheet and without even looking at the html or knowing anything about the html you can predict exactly which rule will be applied (assuming valid rules for that element) as the position in the html is unimportant.

Thanks, Paul.

Like I said, it doesn’t make sense to me that something applied directly to an element can get overridden by the “generic” base on the parents (guess that’s the programmer in me), but I know I need to re-configure my understanding of it, and more importantly, re-configure my co-workers understanding as we’re making more and more use of LESS (personally, I’d rather use less LESS and more straight css) and these situations are going to come up more and more.

You see, I never had this problem :slight_smile: (Well maybe just a little)

All elements have rules applied to them - (whether you like it or not). These rules can come from far and near and through a process of conflict resolution you end up with styles applied to that element. Some styles are from UA styles, some styles may be from user stylesheets some styles are from author stylesheets and some styles are inherited from the parent’s styles.

I think you may be confusing inheritance with specificity a little as inheritance has nothing to do with specificity really. A child will inherit certain properties from its parent should no more specific styles apply. If for example you set a div to have a font-size of 40px then its children will inherit that 40px font size unless there were more specific rules.

e.g.


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Untitled Document</title>
<style type="text/css">
#test #test2 { font-size:40px }
p.not40 {font-size:13px}
</style>
</head>

<body id="test">
<div id="test2">
		<p class="not40">Test</p>
</div>
</body>
</html>


In the above the p element would have a font-size of 13px because rules that apply specifically to the p element are only the simple class called .not40. The heavyweight id selectors are targeting the parent div and not the p element. Remove the class from the p element and the p element will then inherit the font-size from the parent div. Alternatively change the first rule to say “#test #test2 p” and then that rule will win out. It seems to me that this is what you are confusing with rules that actually apply specifically to that element.

The C in CCS is not called cascading for nothing.:slight_smile: Unlike scripting it’s an amalgamation of rules that finally style the element and those styles could be a combination of rules from many sources.

The way I see it, in simple terms, is that both “[yadda yadda] ul” and “#allsteps” are directly targeting <ul id=“allsteps”>, so it isn’t down to inheritance or anything else, it’s just a fight to the specificity (and yes, I can say it!).

As TechnoBear said in #2, “[yadda yadda] ul” has three IDs, whereas “#allsteps” only has one. Therefore “[yadda yadda] ul” is more specific than “#allsteps”. If one rule has more IDs than another, it wins, end of story, game over.

This does raise the question as to why you need “#advertiser #centerContentContainer #edit_listing td ul”. Surely “#edit_listing td ul” would be just as good? Of course, you’d still need “#edit_listing td ul#allsteps” to beat it, but it’s easier CSS, as well as being less processor intensive to parse.

No, [URL=“http://www.apress.com/programming/css/9781590597323”]Pro CSS Techniques](http://easy-readers.net/). (I hope I’m allowed to link to that.)

Off Topic:

You sure are :slight_smile:
The only links we don’t like are self promotional links. Well, that and spam of course.

Kind of off-topic here, but about a year ago I almost completely stopped using ids, using classes instead. It has made my style sheets a lot simpler, as classes are a lot easier to override than ids and have a lot more uses. I basically reserve ids for JS and on-page links now.

PS Unless I missed it above, CSS does offer !important as an escape clause, though I’ve never actually resorted to it. E.g.

#allSteps { margin-left: 0 !important}

Actually ids have a lot more uses than classes.

In HTML you can link to an id - you can’t link to a class. <a href=“#here”>jump</a> links to <p id=“here”>
In JavaScript all browsers support getElementById but only some of the more modern ones support getElementsByClass and even those that do require a loop to process them all.

That’s what I meant by my poorly phrased comment:

Felgall is right.

I use this to keep my mind straight about specificity.

(pseudo classes aside)
The greater count of tags beats the lower count.
ONE CLASS beats any count of tags (w/o classes).
The greater count of CLASSES beats the lower count.
ONE ID beats any count of classes and tags (w/o IDs).
The greater count of ID beats the lower count.
You can add lower value items to break ties…(ex: div .menu or even ul.menu beats .menu)
IN CASE OF ABSOLUTE TIE, for any of these situations, what ever is last in the stylesheet wins.

If you keep in mind those guile lines and the fact that CSS rules do not determine a PATH to an element per se… everything about specificity becomes transparent.

@dresden_phoenix - That’s a nice simple summary.

I eventually got my mind round specificity when I decided that the W3C had used the wrong name for it. :wink: I agree with DaveMaxwell that an id attached to a tag should be regarded as more specific than three ids attached to ancestors. So I gave up thinking of rule “specificity” and started thinking about rule weight, which (for me) simplified things no end. Three of something clearly weighs more than one of something, irrespective of position, so that rule should win out.

Slightly Off-Topic:

I’d never heard of LESS until I came across it on the forums, and I decided just now to follow the link and learn more about it. Well, that’s another thing that’s misnamed. It shouldn’t be called LESS CSS, it should be called NO CSS, because that’s what you get if you have Javascript disabled. (Apart from the one in-line style used to place an image over the text so it’s difficult to read.) This is progress? :rolleyes: I’m afraid I still don’t know any more about LESS than that, because I lost interest at that point.

Sorry it’s taken so long to get back to this thread - had a power outage and downed trees (onto cars) over the weekend, so I’m just now getting back to this thread…

That’s a definite possibility, but like I’ve said before, I didn’t understand why a id style that matched directly on an element would be overridden by a cascading style. Yes, I now (mostly :shifty:) understand the count types of rules - doesn’t mean I have to agree with them. The logical side of me says the process should be (yes I know it doesn’t, but I feel it should)

  • Apply any styles which match exactly by id with highest precedence
  • Apply any styles which match exactly by class next
  • Apply any styles that cascade from there…

Oh, I understand that - it’s this particular scenario which seems bass-ackwards to me…

I don’t like to use !important as it can cause other issues - I’d rather just simplify the styling…

Glad I’m not the only person who thinks this way :smiley:

Luckily, we use it more as a developmental tool than truly “LESS”, and we build the css files when we move to production. We’re not using the full power of it (nor do we need to), and as we’re still feeling out what needs to be done, we’re following the KISS principle before going live…