views:

93

answers:

6

I'm stunned by a simple thing that I want to accomplish but does not work. I have a website and I want it to support themes, which are a named set of CSS + images. No matter which theme is selected, I always include the main CSS file, which is the default theme. On top of that I'm loading a second stylesheet, the one that is theme-specific, like so:

<link rel="stylesheet" type="text/css" href="css/main.css" title=main" media="screen" />
<link rel="stylesheet" type="text/css" href="themes/<?= $style ?>/css/<?= $style ?>.css" title="<?= $style ?>" media="screen" />

My idea is that the theme specific css should not be a full copy of the main css file. Instead, it should only contain CSS rules that overrule those of the main.css file. This makes themes much smaller and easier to maintain.

I thought I could simply load two external stylesheets after each other and that for conflicting rules it will always use the theme specific css, the second file.

However, it does not seem to work. If I make a dramatic styling change in the theme file then it has no effect. If I then comment the main CSS file, the theme CSS does have effect.

Was I too naive in expecting this to work like this? I know I can use inline styles to overrule anything, but I prefer a setup like this if possible.

+2  A: 

In concept that should work IF the rule in the second style has the same level of specificity as the rule in the first stylesheet. For example:

/*stylesheet 1 */
#somediv {
    width: 300px;
}

/*stylesheet 2 */
#somediv {
    width: 500px;
}

In this case the rule in the second stylesheet should take presidence over the rule in the first stylesheet since they both have the specificity.

/*stylesheet 1 */
div#somediv { 
    width: 300px;
}

/*stylesheet 2 */
#somediv {
    width: 500px;
}

In this case the rule in the first stylesheet has presidence over the second stylesheet as the div element in the rule adds more presidence to the rule.

You can increase presidence by using !important to a rule which virtually gives it highest presidence regardless of anything (sort of):

/*stylesheet 1 */
div#somediv { 
    width: 300px;
}

/*stylesheet 2 */
#somediv {
    width: 500px !important;
}

In the above case the rule in the second stylehseet takes presidence thanks to the !important declaration.

Keep in mind that if you don't explicitly overwrite a rule it carries over to any subsequent stylesheets that follow.

John Conde
Thanks John. Yes they do. As a simpel test I'm setting the background of the main CSS html {} rule to white and the background of the theme css html {} rule to black. It only shows white :(
Ferdy
Your first example is what I want, and that is the one that does not work, alo not with the use of !important
Ferdy
+1  A: 

I would start by using FireBug with FireFox to see which rules are winning. Firebug will also show you if your secondary css file is even loading.

Additionally the second css file's rules may not have enough strength to beat the main css file. Use the !important keyword on individual rules to see if this is a problem. I would only use !important for debugging.

See this link about css specificity scoring

Example Main.css

#content a.mylink { color:red }

Example theme.css

#content .mylink { color:blue }

The main.css's rule for mylink will win because its more specific

Tim Santeford
Trust me, the rules in the theme css are exactly the same in structure, the only difference is their value. I tried using Firebug on the html element (which is white in main, and black in the theme), Firebug shows it is taking the html rule from main.css.
Ferdy
Is firebug showing that the theme.css rule is getting overruled? Does it show that rule crossed out that is?
Tim Santeford
I would look at the Net tab on firebug to make sure there is nothing suspicious. I have seen strange file serving problem with development servers like xampp.
Tim Santeford
Looked at the Net tab. Both CSS files load fine. Both Firebug and web developer toolbar show that the element I am testing gets set by that element in main.css, not from the theme.
Ferdy
Just to be clear, does firebug show the theme's rule but is crossed out? Is there some serious syntax error in the theme.css. I think I would comment out all rules in the theme.css except the one rule your testing.
Tim Santeford
That's the weird thing, it does not show the theme rule at all, somehow it is not *seeing* it. When I comment the link to main.css, the theme CSS works just fine. Stripping it down to just one test rule does not make a difference either. I am positive that the links to the files and their mime types are correct. Puzzled I am.
Ferdy
I just noticed that your example code has a syntax error on the main.css line. there is a missing quote.
Tim Santeford
Yeah, another person on the thread noticed that too. I fixed it but unfortunately it still does not solve the problem. Thank you for your persistence though.
Ferdy
Did you try manually entering the theme's css url? I have had problems using php short tags when the server was not configured correctly.
Tim Santeford
Yes. I do view source in Firefox and then click through on the CSS link. That opens the content of the theme CSS.
Ferdy
+1  A: 

No, it should be working as you expect it to work. It's possible the typo in your code is causing your second stylesheet to not load?

<link rel="stylesheet" type="text/css" href="css/main.css" title=main" media="screen" />
                                                                 ^ forgot the quote

If after fixing that it still doesn't render correctly, try using a tool like Firebug to view the styles you are trying to override and see what is going on.

Lance McNearney
Thanks for pointing that out. Unfortunately, it does not solve the problem.
Ferdy
Ah, well it was just a guess. From looking at the other answers and comments you may be at the point of having to provide a live example so we can re-produce the issue and suggest a solution.
Lance McNearney
+1  A: 

You will need to make sure to use the same selectors in the theme stylesheet. CSS gives priority to the more "specific" selectors no matter what order the sheets are in.

For example:

#content p {
    color: #000;
}
body #content p {
    color: #ccc;
p {
    color: #999;
}

Here the computed color will be #ccc, since it is defined in the most specific selector. If you want to override it, simply put this in your theme sheet:

body #content p {
    color: #000;
}
Daniel
I am using the exact same selectors, so that does not explain my problem so far. Scoping should not be an issue.
Ferdy
A: 

Sounds to me like the value to your css elements is not the same, You can over ride the style with the second style sheet by making sure the rules has the same or higher value.

e.g. 1st style sheet

div.content h1 {my rules} //score 12

2nd style sheet

div.container div.content h1 {new rules} //score 23

The second style sheet in theis case has a higher value so will be used. Css scoring following these simple rules

  • HTML Element - Ones
  • Class - Tens
  • ID - Hundreds
  • Inline Styles - Thousands

Also use firebug to inspect the elemtens and see which is being over ridden.

TheAlbear
+1  A: 

I think your problem is in the title attribute of the link tag. You can't have multiple css files with varying titles (I see you are dynamically naming the titles for themes). They either all have to have the same title - or only the first style sheet can have a title. This is and odd bug - much better explained here:

http://blogs.telerik.com/dimodimov/posts/08-05-15/title_attributes_in_css_link_tags_prevent_styles_from_being_applied.aspx

But I am guessing removing the title attribute will completely solve your problem. This has tripped me up before.

Adam Morse
Whoohoo! That was it. Man, I was going crazy over this. Thanks!
Ferdy