Adding Variables to CSS
Goal

Make it MUCH easier for customers to brand Web-based products
Note that the primary goal here is NOT to make it easier for developers to create CSS files. The primary goal is for CUSTOMERS to more easily modify CSS files. In other words, even though we could modify CSS in much more dramatic ways to make it easier for developers to create these files, the goal here is not developers, rather end users. So, the CSS file needs to remain as user friendly and familiar as possible while still making it much easier to brand the CSS.
Problem Statement

- CSS files usually contain hundreds of color and font codes
- Color and font codes that should be the same are sometimes slightly different. E.g., dark gray is sometimes #333333; sometimes #313233. Dumb.
- It’s very difficult for customers to find, understand, and properly change these codes
We need to find a solution that makes it easier for customers to modify our CSS files without having to hunt-and-peck for the relevant colors codes.
Solution 1
- A wonderful package supporting all of the latest proposed CSS features such as variables, mixins, operations, functions
- I’d love to use this package. However:
- it is written in JavaScript and therefore requires Node.js and Rhino
- that’s 68MB worth of files I need to lay down on customers’ computers
- over > 5000 files
- from Java, would have to do an external execution in order to compile our CSS files
- Even if I automated this work, it’s an awful lot to ask of customers just to have variables in CSS
I can’t use Less because I need to find a solution that consumes very little resources to compile the CSS
Solution 2
- Like Less, a package supporting all of the latest proposed CSS features including variables, mixins, operations, functions, nested rules, conditional expressions, and more.
- From a developer’s perspective, this is the package I’d choose (I think it’s slightly better than Less).
- However I can’t for many of the same reasons as Less:
- it is written in Ruby (a great language) and therefore requires a Ruby interpreter on customers’ computers
- For a Windows environment, that’s 30MB worth of files I need to lay down on customers’ computers
- over > 93,000 files
- and like Less, I’d still have to do a slow, external execution environment offering little control over the compilation of our CSS files
- Even if I automated this work, it’s an awful lot to ask of customers just to have variables in CSS
I can’t use Sass because it requires Ruby and lots of resources to compile the CSS. I need something that is light-weight, preferably runs in Java, and allows me to make tweaks should I need to.
What’s Coming in CSS
- CSS Variables is already in draft form
- CSS Mixins is currently in proposal form
- Variables, mixins, and nesting are already in WebKit (in an experimental form)
Looks like whatever solution I find, it’s going to be somewhat temporary since the W3C is already under way to add some of these awesome features into CSS.
The ideal solution would not only be easy to use for customers, but would also easily migrate to the standard solution once that’s fully supported by all browsers in a year or two.
Seeing that the goal is to make it easy for customers to brand our CSS, the ideal solution will look as much like standard css as possible. In other words, it will NOT use all these new Less and Sass CSS features. Bare minimum is best.
Solution 3
- ZUSS is a pure Java package; that’s good already since that means it can be part of my standard development environment. I can use either the jar directly, or modify the source code as needed.
- It’s tiny
- 89K (Wow!! — compare that to Less and Sass above)
- 73 files in 1 jar (again Wow!)
- ZUSS supports most of the new CSS features the other packages support:
- Variables
- Mixins
- Nested Rules
- Functions
- Includes
- Conditional Expressions
- ZUSS provides a small servlet that compiles the CSS files on demand (when requested from the browser)
- This allows our CSS to be either in a War file (which is how Web products are usually distributed) or in an external directory where customers could copy and edit the files.
- Caches CSS for future requests
- Recompiles as CSS files are changed
- ZUSS is licensed under the GNU Lesser GPL which means it’s very developer and distribution friendly
Fonts
Here’s how a font is defined in my new CSS:
@global-font-family()
{
font-family: Helvetica, Arial, sans-serif;
}
Notice that it begins with an @ symbol. This designates a variable in the ZUSS language. In other words, global-font-family() becomes a mixin when used.
Notice also that global-font-family() contains a full CSS attribute declaration: font-family: Helvetica, Arial, sans-serif; We could have included any number of other attribute definitions, for example size, color, margins, line height, font weight and style, etc. Anything placed within the braces is included when used elsewhere in the CSS file.
Here’s the mixin used elsewhere in the CSS:
.welcomeHeader
{
@global-font-family();
font-size: 2em;
}
Sweet !!
Colors
Here’s how a color is defined in my new CSS:
@product-color: #8cc63f; /* product name in nav bar, links, quote bin header, active button background, slider value, bread crumb sep */
Any time I want to use that color, I simply:
.headerLogoText
{
color: @product-color;
}
Functions
If you paid attention to the comment in the color variable defined above, you’ll note we’re using that same color in lots of areas throughout the product. A good 15 places use that color directly, as is. However, buttons have gradients, hovers, and pressed states. Links change colors when hovered or visited.
And we’d like to use a “faint” version of the color when selecting items in rows. Rather than having the customer specify all the variants of a given color, wouldn’t it be cool if we could automatically “derive” the color from the primary color. That way, all the customer has to specify is a single color …and none of its variants.
ZUSS offers two kinds of functions to do this type of task:
- A simple function defined in CSS permitting basic math functions and color manipulations
@lighten(@color, @diff: 10%): @color * (1 + @diff);
- Java-defined functions that can be called directly by our CSS and can provide any range of sophistication
@lighten(@color, @diff: 10%): @import com.netiq.agility.client.internal.ColorUtils;
We chose to go with the more sophisticated Java-based functions permitting more accurate color calculations.
- Here’s our ColorUtils.java class in which we created a series of high-fidelity color rendering methods
- These are based on the HSB (Hue, Saturation, Brightness) color model which is also supported by the basic Java Color class and by Photoshop.
- It’s much easier to make a color brighter by simply adjusting the “brightness” factor than trying to calculate Red, Green, and Blue values.
Derived Colors
Now that we have color variables and high-fidelity color manipulation routines, let me show you what we did for the single “product color” which I think you’ll agree most Web interfaces have:
/* User-provided Colors */ @product-color: #8cc63f; /* product name in nav bar, links, quote bin header, active button background, slider value, bread crumb sep */ /* Derived Colors - users do NOT need to edit these colors */ @product-color-lighter: @lighten ( @product-color, 15% ); @product-color-darker: @darken ( @product-color, 15% ); @product-color-hover: @highlight ( @product-color, "-92%" ); @product-color-hover-lighter: @lighten ( @product-color-hover, 3% ); @product-color-hover-darker: @darken ( @product-color-hover, 5% ); @product-color-select: @highlight ( @product-color, "-78%" ); @product-color-select-lighter: @lighten ( @product-color-select, 3% ); @product-color-select-darker: @darken ( @product-color-select, 5% ); /* hover */ @active-bhover-color: white; @active-bhover-background-color: @lighten ( @product-color, 10% ); @active-bhover-background-start: @lighten ( @active-bhover-background-color, 5%); @active-bhover-background-end: @darken ( @active-bhover-background-color, 12%); @active-bhover-border: @darken ( @active-bhover-background-color, 15%); @active-bhover-shadow-color: @shadow ( @active-bhover-background-end ); /* pressed */ @active-bdown-color: black; /* invert the hover color */ @active-bdown-background-color: @darken ( @product-color, 5% ); @active-bdown-background-start: @active-bhover-background-end; /* invert the hover color */ @active-bdown-background-end: @active-bhover-background-start; /* invert the hover color */ @active-bdown-border: @darken ( @active-bdown-background-color, 12% ); @active-bdown-shadow-color: @shadow ( @active-bdown-background-end );
We’ve created 20 variants on the primary user-provided “Product Color”. These 20 colors are then used throughout the CSS whenever a product-color-related accent is desired.
- Links (normal, hover, visited)
- Buttons (gradients for normal, hover, pressed)
- Product logo
- Header colors
- Scroll bar thumb
- Bread crumb separators
- Triggers in various UI widgets (combo, spinner, date picker, etc.)
- List selection and hover
- many other UI elements use versions of the product color !
In all, there are hundreds of places throughout the CSS where these 21 colors are used.
I think you’ll agree, that’s a lot of benefit for the customer …and they only had to define 1 color value to do so !!!
Note that in our final implementation, we ask the user to define approximately 15 primary colors in a single location at the top of the CSS file. And that’s it. Press refresh in your browser, and the entire color scheme changes throughout.
Includes
To make our files even simpler, we used ZUSS’s include ability to hide our function declarations and derived color definitions in separate include files that our customers will never see as they edit the CSS to make their own Themes.
@include functions.ncss; @include derived_colors.ncss;
Provide a Theming Generator
Come to think of it, now that our CSS is sssssoooooooo simple, we could very easily produce a simple dialog within our product that allows the user to define the colors right from the UI …rather than having to find/copy/edit/save the CSS in the file system.
This “Theme Creator” dialog would be very simple to create. Just ask for a small set of color and font definitions, show examples of each in action, ask for a Theme name, and that’s it.
I’ll leave this for a future exercise to blog about.




I haven