tags:

views:

1070

answers:

6
+1  Q: 

CSS precedence

My webpage contains:

<link href="/Content/Site.css" rel="stylesheet" type="text/css" />
<style type="text/css">
td {
    padding-left:10px;
} 
</style>

The referenced stylesheet contains:

.rightColumn * {margin: 0; padding: 0;}

I have a table in the rightcolumn ID where I want the cells to have a little padding. However, the referenced stylesheet is taking precedence over the inline styling. I see this visually and also via Firebug. If I turn off the padding:0 instruction in Firebug, the padding-left takes effect.

How can I get the padding-left to work?

+3  A: 

The easiest way to get it to work is to add "!important" to CSS to guarantee its precedence (unless you've got multiple !important rules):

td {
    padding-left: 10px !important;
}

If you're looking for an answer without !important, you should read into CSS specificity specifications. The linked site has a good explanation of how it works, though basically it goes from most important to least, with id selectors most important, class selectors second, and element selectors third.

Daniel Lew
Watch out when using !important. It will increase maintenance problems if you have other people working with the code that aren't familiar with your usage of the !important rule.
Rahul
Not to mention it breaks precedence which is confusing if you are looking at a rule that ought to be applied but isn't.
Andrew Hare
I agree that !important should be used sparingly, but I find it similarly problematic when someone starts over-complicating their selectors just so they are more specific. For this example, it'd be td.rightColumn * { ... }, which is a horrific change to an otherwise simple selector.
Daniel Lew
+1  A: 

Try this instead:

td.rightColumn * {margin: 0; padding: 0;}

The td in the external stylesheet is more specific so it wins out. If you qualify the rightColumn class with an element name then the page-level styles will be applied.

Andrew Hare
A: 

You could try adding the ! important flag to your inline css.

e.g.

td { padding-left:10px ! important; }

Also, for general rules on css rule ordering, have a look at this :

http://www.w3.org/TR/CSS2/cascade.html#specificity

deanWombourne
Wow, this was my first question posted to StackOverflow. I thank you all for your responses. They made me think more deeply about the issue.
A: 

Do this:

.rightColumn *,
td.rightColumn * {
  margin: 0;
  padding: 0;
}

Precedence in CSS is as follows:

  • If some rule has an ID, then it will precede anything else.
  • If some rule has a class attribute, it will precede tag-only rules.
  • If two rules have both IDs or tags, then the number of them untie the "fight".

Example:

<style type="text/css">
  #myid{
    padding: 10px;
  }

  .class{
    padding: 20px;
  }
</style>
<div id="myid" class="class"></div>

Although your div has both ID and a class, the ID rule will override the .class rule.

To read more about CSS rules priorities, I'd recommend http://www.w3.org/TR/CSS2/cascade.html#specificity.

Seb
+1  A: 

As others have mentioned, you have a specificity problem. When determining which of two rules should take precedence, the CSS engine counts the number of #ids in each selector. If one has more than the other, it's used. Otherwise, it continues comparing .classes and tags in the same way. Here, you have a class on the stylesheet rule, but not on the inline rule, so the stylesheet takes precedence.

You can override this with !important, but that's an awfully big hammer to be using here. You're better off improving the specificity of your inline rule. Based on your description, it sounds like your .rightColumn element either is or contains a table and you'd like the cells in that table to have extra spacing? If so, the selector you're looking for is ".rightColumn td", which is more specific than the stylesheet rule and will take precedence.

Ben Blank
+2  A: 

Most of the answers are correct in saying that this is a specificity problem but are incorrect or incomplete in explaining the specificity rules.

Basically in your case .rightColoumn * is "more specific" than td and so that rule wins even though it comes earlier.

The CSS 2.1 rules are located here. These rules are:

  • count 1 if the declaration is from is a 'style' attribute rather than a rule with a selector, 0 otherwise (= a) (In HTML, values of an element's "style" attribute are style sheet rules. These rules have no selectors, so a=1, b=0, c=0, and d=0.)
  • count the number of ID attributes in the selector (= b)
  • count the number of other attributes and pseudo-classes in the selector (= c)
  • count the number of element names and pseudo-elements in the selector (= d)

Concatenating the four numbers a-b-c-d (in a number system with a large base) gives the specificity.

So in your case you have two rules:

.rightColumn * {} /* a = 0, b = 0; c = 1, d = 0 : Specificity = 0010*/
td {} /* a = 0, b = 0, c = 0, d = 1 : Specificity = 0001 */

0001 is lower than 0010 and thus the first rule wins.

There are two ways to fix this:

  1. Use !important to make a rule more "important". I'd avoid doing this because it is confusing when you have lots of rules spread out over several files.
  2. Use a higher-specifity selector for the td you want to modify. You can add a class name to it or an id and this will allow you to supersede the rule from the linked CSS file.

Example:

<style>
  .rightColomn * { padding: 0; } /* 0010 */
  td#myUnpaddedTable { padding: 10px; } /* 0101 */
  td.anUnpaddedTable { padding: 10px; } /* 0011 */ 
</style>

Edit: Fixed the specificity rules for *. David's comment prompted me to re-read the spec, which does show that the * selector contributes nothing to the specificity score.

Mr. Shiny and New
I concur. Based on the W3C page, though, I don't think that the star selector counts towards d-level (or any-level) specificity, so .rightColumn * should score 0010. I'd also recommend .rightColumn td {} as way to set the padding; it yields a good-enough score of 0011.
David Kolar
@David Kolar: Thanks, fixed.
Mr. Shiny and New