This was certainly true when CSS was a "set once, style forever" technology.
However, that's no longer how we build webpages. Modern websites use dynamic styling, by manipulating css declarations for elements and classes, using selectors-based manipulation (jQuery, MooTools, document.querySelector, etc). Even though a designer can write CSS in such a way that it's obvious which elements share which declarations, for instance by using "p, li, a { color: #333; }", shared declaration are lost after the CSS is loaded. The CSS engine throws that implicit information away, and binds rules separately for each element indicated.
You might not think that's reason enough to want CSS variables, using the counter argument to "use classes". While for a low number of shared declarations, for a low number of elements, this might seem a good idea, for modern websites, with dynamic styling, that becomes intractible. Let's look at a realistic scenario where a set of {p, span, pre, ul, ol, li, h1, h2, h3, h4} might have shared styling for fonts for {p, span, li}, shared text color styling for {p, pre, li, h1, h2, h3, h4}, shared border styling for {pre, ul, ol} and different shared border styling for {p, span, h1}, shared offsets for {pre, ul, ol, h2, h3, h4} and shared backgrounds for {pre, ol, ul}. Modifying the shared style now requires either:
So neither of these options are very attractive.
CSS macros. You can solve the above problem relatively simply with some CSS variables, so that's why the JavaScript solution presented on this page exists: it makes implementing a design a lot easier. Now, it's not perfect: it requires JavaScript, which means that if you want to do it right, you have to write fallback rules (such as a "style-no-js.css" file, or double declarations for elements) for browsers that don't do JS —not just old browsers, but also current browsers with NoScript or the like enabled— and then write your dynamic, manipulable CSS with macros as second stylesheet. Of course you should already be writing fallback rules if you're using dynamic CSS, so it's not really going to change a ridiculous amount on that front. It just makes applying and changing design styles on-the-fly a hell of a lot easier.
Download the following JavaScript include and it will add macro capabilities to the CSS engine (technically, to JavaScript) when included, so that you can do this:
@macros { text-font: Georgia; text-font-color: #06A; standard-border: 1px solid #66F; subtle-border: 1px solid #999; quote-margins: 0em 2em; block-bg: #dd9; } p { font-family: text-font; color: text-font-color; } span { font-family: text-font; color: text-font-color; } pre { padding: 5px; color: text-font-color; border: standard-border; margin: quote-margins; background-color: block-bg; } ul{ border: standard-border; margin: quote-margins; background-color: block-bg; } ol{ border: standard-border; margin: quote-margins; background-color: block-bg; } li{ font-family: text-font; color: text-font-color; margin-right: 1em; } h1,h2 { border-bottom: subtle-border; } h1,h2,h3,h4{ color: text-font-color; padding-left: 0.2em; } h3,h4 { margin: quote-margins; }
Without everything breaking.
I don't like LESS because I find the syntax horrible. I am someone who genuinely doesn't understand why he needs to use special syntax to mark a variable as such when there's only one place where it can be used. It's one of the things I like about Java and JavaScript: if its role does not conflict with anything, don't add syntactic sugar to emphasis that role. I also don't like how its syntax doesn't keep with CSS conventions. It makes a LESS flavoured CSS file look like a coding kludge. It's just not for me.
I do like SASS, but it doesn't solve the problem of the CSS engine taking apart your grouped declarations and wiping out the shared design elements. Changing the design on the fly is still as impossible with SASS as it is without it. As SASS is a serverside "you write a much nicer kind of stylesheet, and the SASS compiler turns it into CSS for use on your webpage" technology. This means that at the client, SASS generates exactly the same kind of CSS as you currently use. The generation process is just much nicer.
However! If you use SASS, you can safely combine it with cssmacros.js and still have the benefit of client-side css macros ('constants' or 'set-once variables') while being able to write your styling in a far more sensible stylesheet language. If your setups support ruby, use both!
Add the JavaScript include to your page's <head> element:
<script type="text/javascript" src="cssmacros.js"></script>
Then, simply add the following rule to the top of your CSS:
@macros { macro_1: value; macro_2: value; ... }
and you can use those macros in the rest of your stylesheet:
p { color: macro_1; background-color: macro_2; ... }
But remember that just like for any other dynamic CSS, you need to declare fallback values, or you risk looking horrible before people enable scripts (or upgrade to a better browser :)
You can also declare global macros for use in any stylesheet in which case you'll want to use @global-macros {} instead:
@global-macros { macro_1: value; macro_2: value; ... }
and you can use those macros in any stylesheet. Because the macros aren't replaced until DOMReady is signalled, you can even effect macro replacement in stylesheets that are loaded before the stylesheet that has a global macros block.
Additionally, you are not limited to a single global macros block. You can declare as many as you like, as long as you observe these two properties:
Macros declared using @macros {} are stylesheet-specific, and the base functionality is tied to individual objects in the document.styleSheet array (CSSStyleSheet objects, to be precise). There is also a general purpose "do this for all stylesheets" API, so you get access to the following base functions:
The general purpose styleSheets.(g/s)etMacro require the stylesheet's href value, so if you're using "style.css" then you use that are first argument.
If you're using jQuery, you also get access to a .macro() function that is similar in functionality to the jQuery .css() function:
The first returns a single value, the second a standard jQuery set after applying the modification. To modify a specific style sheet, you simply specify this in your selector:
var focalColor1 = $('link[href="style.css"]').macro("focal-color-1");
Obvious this page uses css macros, so let's apply some changes:
These changes are all effected by single calls, only modifying the macro value for the indicated macro. No selectors or classes are used, so you can't "forget" elements in a selector. If the CSS says that macro is used, then changing its value applies to everything that uses that macro. It's that simple.