[Newbie] Basic question about specifity / element / order

Having the simple code:

<html>
<head>
<style type="text/css">
#red p {
	color: #F00;
}
.blue {
	color: #00F;
}
</style>
</head>
<body>
<div id="red">
<p>Should be a red paragraph</p>
<p class="blue">Should be a blue paragraph</p>
</div>
</body>
</html>

Why is the second paragraph still red? What’s the solution to make it blue?

Thanks.

In your stylesheet you are using #red p. The problem with this is that it targets all the p tags in the #red div and overrides your second line of css.

There are a number of ways to fix this, one of them is to give each <p> a class and target them individually like so:


<html>
    <head>
        <style type="text/css">
            .red {
            color: #F00;
            }
            .blue {
            color: #00F;
            }
        </style>
    </head>
    <body>
        <div id="p-wrapper">
            <p class="red">Should be a red paragraph</p>
            <p class="blue">Should be a blue paragraph</p>
        </div>
    </body>
</html>

Or a more advanced method is to add :first-child to the #red div like so (first-child as it’s name implies, will only target the first element of whatever you are selecting; in our case the <p> tag):

<html>
    <head>
        <style type="text/css">
            #red p:first-child {
            color: #F00;
            }
            .blue {
            color: #00F;
            }
        </style>
    </head>
    <body>
        <div id="red">
            <p>Should be a red paragraph</p>
            <p class="blue">Should be a blue paragraph</p>
        </div>
    </body>
</html>

Ok, but why does the ‘#red p’ overrides the ‘.blue’ class? That’s what I don’t understand :slight_smile: .

Block level elements such as <div> and <h1>, <h2>, <h3> etc, have precedence over inline elements. You’ve given your <div> an id of #red and selected all the <p>'s in that div, and because you have given your <p> tag (an inline element) a class of .blue it doesn’t have as much precedence and is therefore ignored.

But <p> is also a block level element, as <div>…

Both ‘#red p’ and ‘.blue’ are targeting the paragraph. There’s a conflict. One says it should be red, the other says it should be blue. Conflict resolution says … if one declaration lists more IDs than the other, that one wins.
#red p’ lists one ID, and ‘.blue’ lists no IDs. So ‘#red p’ wins, doing a victory jig over '.blue’s dead body, and the paragraph turns red.

If the red dec was just ‘#redwithout the ‘p’ then it would be a different story. Then the ‘#red’ declaration would not be specifically targeting the paragraph, but the paragraph’s parent. The default colour is ‘inherit’ (ie, whatever the parent is), so if nothing else is specified for the paragraph, it is red. But then you have ‘.blue’, which comes along and tells the paragraph not to inherit the colour of its parent, but instead to be blue. So then it’s blue.

Say what? Styling on block-level elements does not win out over styling on inline elements – in fact, it’s usually the other way round.

p {color:red;}
span {color:green;}

<p>Here's a red paragraph <span>with some green words</span> in the middle</p>

Styling declared on the inline element will almost always overrule styling declared on the parent element, because it’s targeting the actual element rather than its parent.

A <p> is a block-level element anyways (was coding a WP theme for a client while I posted that, multi-tasking was never one of my strong suits :rolleyes:). Totally messed that up, don’t know what I was thinking :blush:.

Am sorry I think I have missed most of the post, the answer here is SPECIFICITY. I has nothing to do with block or inline.

SPECIFICITY overrules the cascade… no matter what!

That means :
A class will overrule a tag in the style sheet, an ID will in turn overrule a class and if you should ( perish the thought) write your CSS in the mark-up inside the tag itself it will overrule EVERYTHING ELSE.

By the described order above :
#red p {} will override rules like : p{}( a tag), .blue {}(a simple class), and even p.blue{} ( a class and tag) since you started with an ID and a tag… in order to override that rule… you will need AT LEAST an ID and a tag. #red p {} (will target all the Ps and its not what we want so we need something like #red .blue {}

expounding on this:
if you had written:
.red p {}
.blue{}

it will would not work as a class+ a tag is still > just a class

HOWEVER this would work
.red p {}
p.blue{}

AND THIS would not.

p.blue{}
.red p {}

when the specificity total is the same (class+tag)=(class+tag) then rule that is latter the stylesheet wins.

hope that clears this all up for you.

For more information on specificity, check out the SitePoint CSS Reference. It has a nice summary of how specificity is calculated.

CSS: Specificity Wars | And all that Malarkey

I couldn’t have said it better that Dresden did :agree:

Thanks, Dresden, you saved my time :smiley:

So, then what would be the finest soltution to achieve the following:


<div id="firstdiv">
<p>Some paragraph text</p>
<p>Some paragraph text</p>
<p>Some paragraph text</p>
<div class="seconddiv">
<p>Other paragraph text</p>
</div>
</div>

#firstdiv p needs some formatting (eg bottom margin) which is not wanted on the <p> in the #seconddiv.

What’s the best way to address the “Other” <p> to change its CSS?

What you want to do there is make a rule that only targets the <p> elements in the #firstdiv. You can do that with:

#firstdiv > p {margin-bottom: 30px;}

That will only add bottom margin in the <p>s directly inside #firstdiv, and will leave those in .seconddiv alone.

Be aware, though, that IE6 doesn’t recognize the > selector, so you’d need a more long-winded solution to cover that browser, such as

#firstdiv p {margin-bottom: 30px;}
#firstdiv .seconddiv p {margin-bottom: 0;}

The first line will add bottom margin to all <p>s, and the second line will override the first line for the <p> inside .seconddiv.

Ahh, that’s where I was confused and wrong.

#firstdiv .seconddiv p {margin-bottom: 0;}
does the trick, but just
.seconddiv p {margin-bottom: 0;}
does not.

Thank you all for your help!

Yes, and the reason is one of specificity. An id (#) carries a lot more weight than a class (.), so the id wins out. So to make the override more specific, you have to include an id. It’s now more specific because it contains an id and a class, which has more weight than just an id.

I’d still go with the simpler solution, though, unless you must support IE6. Even then, you could put the IE6 style in a separate, IE-only style sheet, or serve it up with a hack, such as

* html #firstdiv p {margin-bottom: 30px;}
* html #firstdiv .seconddiv p {margin-bottom: 0;}

Except for rules using !important but I know what you meant :slight_smile:

Because !important is really !important… but it is better not to use it unless you have a terrific reason for it… and no, setting up the size of the characters is not a good reason :lol:

I learned something reading this. I always though the cascading nature of CSS dictated that whatever rule came last won. I guess that isn’t true. Thanks.

That only happens when both rules have the same specificity level. Of course, you only notice it when you’re trying to style the same property for the same element in bothy rules :slight_smile: