views:

3673

answers:

17

We have some "theme colors" that are reused in our CSS sheet.

Is there a way to set a variable and then reuse it?

E.g.,

.css OurColor: Blue

{ H1 color:OurColor; }

+3  A: 

CSS doesn't offer any such thing. The only solution is to write a preprocessing script that is either run manually to produce static CSS output based on some dynamic pseudo-CSS, or that is hooked up to the web server and preprocesses the CSS prior to sending it to the client.

Konrad Rudolph
+1  A: 

Since CSS does not have that (yet, I believe the next version will), follow Konrad Rudolphs advice for preprocesing. You probably want to use one that allready exists: m4

http://www.gnu.org/software/m4/m4.html

Daren Thomas
+3  A: 

You're not the first to wonder and the answer is no. Elliotte has a nice rant on it: http://cafe.elharo.com/web/css-repeats-itself/. You could use JSP, or its equivalent, to generate the CSS at runtime.

sblundy
Indeed, the only way to do this is get the server to generate your CSS file which can be done in many ways depending on which language you are using. HttpHandlers are common in C#. You could use jQuery or the likes to add styling to every element with the class 'ourColur' and parametrise your JS
Xian
A: 

No, but Sass does this if you're coding in Ruby on Rails.

Tim Sullivan
Sass is not dependent on rails. You only need ruby to run the script which converts your sass source to css. Otherwise, your site can be built on whatever language you choose.
Andrew Vit
+53  A: 

There's no requirement that all styles for a selector reside in a single rule, and a single rule can apply to multiple selectors... so flip it around:

/* Theme color: text */
H1, P, TABLE, UL
{ color: blue; }

/* Theme color: emphasis */
B, I, STRONG, EM
{ color: #00006F; }

/* ... */

/* Theme font: header */
H1, H2, H3, H4, H5, H6
{ font-family: Comic Sans MS; }

/* ... */

/* H1-specific styles */
H1
{ 
   font-size: 2em; 
   margin-bottom: 1em;
}

This way, you avoid repeating styles that are conceptually the same, while also making it clear which parts of the document they affect.

Shog9
Dude, that is awesome!
Ogre Psalm33
+1 Unfortunately it's still easy (for me) to shoot ones (my) foot with CSS precedence in complex cases -- and in cases like this, just adding one more element to the selector may tip the scale! (So it's very important to keep the CSS tidy and well-organized and try to avoid [excessive] overrides.)
pst
+1  A: 

You're making it too complicated. This is the reason the cascade exists. Simply provide your element selectors and class your color:

h1 {
   color: #000;
}
.a-theme-color {
   color: #333;
}

Then apply it to the elements in the HTML, overriding when you need to use your theme colors.

<h1>This is my heading.</h1>
<h1 class="a-theme-color">This is my theme heading.</h1>
hal10001
This advice goes against the spirit of CSS, which is separation of content and presentation. You way requires changing HTML for presentation sake, and stating in content which elements have same color.
buti-oxa
Clay Nichols
+3  A: 

That's not supported at the moment unless you use some script to produce the CSS based on some variables defined by you.

It seems, though, that at least some people from the browser world are working on it. So, if it really becomes a standard sometime in the future, then we'll have to wait until it is implemented in all the browsers (it will be unusable until then).

Farinha
A: 

See also Avoiding repeated constants in CSS. As Farinha said, a CSS Variables proposal has been made, but for the time being, you want to use a preprocessor.

Sören Kuklau
A: 

@buti-oxa

The separation of content and presentation is inherent to CSS. Again, you are making it way too complicated. Why would the class selector even exist if not for the purpose of adding style to an element? (The current use of class selectors as a way to add behavior (through JavaScript) was not the intended purpose.)

My apologies to everyone, but I cannot figure out how to thread a comment, and that is why this comment shows up as an answer.

hal10001
A: 

See: Why “variables” in CSS are harmful.

cic
Nice article, cic - thanks for sharing!
Shog9
A: 

You can use mutliple classes in the HTML element's class attribute, each providing part of the styling. So you could define your CSS as:

.ourColor { color: blue; }
.ourBorder { border: 1px solid blue; }
.bigText { font-size: 1.5em; }

and then combine the classes as required:

<h1 class="ourColor">Blue Header</h1>
<div class="ourColor bigText">Some big blue text.</div>
<div class="ourColor ourBorder">Some blue text with blue border.</div>

That allows you to reuse the ourColor class without having to define the colour mulitple times in your CSS. If you change the theme, simply change the rule for ourColour.

Simon Forrest
+1  A: 

This may sound like insanity, but if you are using NAnt (or Ant or some other automated build system), you can use NAnt properties as CSS variables in a hacky way. Start with a CSS template file (maybe styles.css.template or something) containing something like this:

a {
    color: ${colors.blue};
}

    a:hover {
        color: ${colors.blue.light};
    }

p {
    padding: ${padding.normal};
}

And then add a step to your build that assigns all the property values (I use external buildfiles and <include> them) and uses the <expandproperties> filter to generate the actual CSS:

<property name="colors.blue" value="#0066FF" />
<property name="colors.blue.light" value="#0099FF" />
<property name="padding.normal" value="0.5em" />

<copy file="styles.css.template" tofile="styles.css" overwrite="true">
    <filterchain>
        <expandproperties/>
    </filterchain>
</copy>

The downside, of course, is that you have to run the css generation target before you can check what it looks like in the browser. And it probably would restrict you to generating all your css by hand.

However, you can write NAnt functions to do all sorts of cool things beyond just property expansion (like generating gradient image files dynamically), so for me it's been worth the headaches.

Matt
A: 
+1  A: 

I've written a macro (in Visual Studio) that allows me to not only code CSS for named colors but to easily calculate shades or blends of those colors. It also handles fonts. It fires on save and outputs a separate version of the CSS file. This is in line with Bert Bos's argument that any symbol processing in CSS take place at the point of authoring, not not at the point of interpretation.

The full setup along with all the code would be a bit too complicated to post here, but might be appropriate for a blog post down the road. Here's the comment section from the macro which should be enough to get started.


The goals of this approach are as follows:

  1. Allow base colors, fonts, etc. to be defined in a central location, so that an entire pallete or typographical treatment can be easily tweaked without having to use search/replace

  2. Avoid having to map the .CSS extension in IIS

  3. Generate garden-variety text CSS files that can be used, for example, by VisualStudio's design mode

  4. Generate these files once at authoring time, rather than recalculating them every time the CSS file is requested

  5. Generate these files instantly and transparently, without adding extra steps to the tweak-save-test workflow

With this approach, colors, shades of colors, and font families are all represented with shorthand tokens that refer to a list of values in an XML file.

The XML file containing the color and font definitions must be called Constants.xml and must reside in the same folder as the CSS files.

The ProcessCSS method is fired by EnvironmentEvents whenever VisualStudio saves a CSS file. The CSS file is expanded, and the expanded, static version of the file is saved in the /css/static/ folder. (All HTML pages should reference the /css/static/ versions of the CSS files).

The Constants.xml file might look something like this:

<?xml version="1.0" encoding="utf-8" ?>
<cssconstants>
  <colors>
    <color name="Red" value="BE1E2D" />
    <color name="Orange" value="E36F1E" />
    ...
  </colors>
  <fonts>
    <font name="Text" value="'Segoe UI',Verdana,Arial,Helvetica,Geneva,sans-serif" />
    <font name="Serif" value="Georgia,'Times New Roman',Times,serif" />
    ...
  </fonts>
</cssconstants>

In the CSS file, you can then have definitions like:

   font-family:[[f:Text]];
   background:[[c:Background]]; 
   border-top:1px solid [[c:Red+.5]]; /* 50% white tint of red */
Herb Caudill
A: 

wro4j java framework has a feature for supporting css variables: http://code.google.com/p/wro4j/wiki/CssVariablesSupport Besides that, you can merge your resources (both: css & javascripts) into a single file & minimize them using a built in or custom minimization processor.

Alex Objelean
+5  A: 

You can achieve it and much more by using Less CSS.

Giorgi