September 20, 2008 will

Colour manipulation in Django

A well-designed website will tend to have a consistent colour scheme where the various design elements sit harmoniously together, yet contrast well enough  that the user can separate them visually. Selecting these colors is a mixture of an art and a science. Its an art because only a human being can know if the colors project the image required by the site (business-like, mellow, funny etc), but it's also a science because complimentary and contrasting colors can be produced from a source colour using only math. As an engineer the math part appeals to me, but the art part "confuses and enrages me" (guess the quote).

A site will tend to have a few core colours, and additional colours that are deduced from the originals. For instance, you might want a pastel shade of one of the core colours as a background and a darker shade to use as a border. You may also want to blend colors together to create soft gradients. Implementing such color schemes with Cascading Style Sheets can be a pain because the colors are repeated throughout the file, and if you want to change a colour -- or all of them -- you need recalculate deduced colours and make numerous changes to the CSS. For someone like me, who doesn't have an intuitive sense of what looks good, it can be a time consuming process to tweak colours through CSS. So naturally I chose to solve this with techie solution.

I hacked together a class called WebColor, which stores and manipulates colour values. Colours can be created from a variety of formats, here are a few examples that create pure green:

c = WebColor( 0.0, 1.0, 0.0 ) #RGB

c = WebColor( "#00FF00" ) # HTML style

c = WebColor("rgb(0,255,0)") # CSS style

c = WebColor.fromHSL(0.333, 1.0, 0.5) # From HSL (Hue Saturation Lightness)

This class was designed to be used in templates, if you print a WebColor object it will render an HTML style color (e.g. #00FF00). So in the context of a Django template you can do {{ my_color }} to produce #00FF00. I've also written a few Django filters to do some common operations on colours. The 'lightness' filter changes the lightness of a colour, and takes either the exact value as a parameter, or a percentage to modify the original. For example {{ my_color|lightness:".2" }} will create a color with the same hue, but with a lightness of .2. Alternatively {{ my_color|lightness:"50%" }} will create a colour that is half as bright as the original. There is also a 'saturation' filter which works in the same way, but adjusts the saturation of a colour. In addition to these filters there are two tags; 'HSL' which creates a colour directly from HSL values, and 'colorblend' which produces a colour that is part way between two other colours. See the code (link below) for more information.

The easiest way to create colour schemes with these filters / tags is to templatize your CSS files and supply the template with your core colours, possibly created with something like Agave, or Kuler. In the project I'm working on at the moment, I have a list of 3 colors called 'palette' and all the other colours used in the CSS are deduced from the palette. For example, the following creates a pleasing alternating background for rows in table:

.chart-grid .even

{

background-color:{{ palette.0|lightness:".94"|saturation:".1" }};

}

.chart-grid .odd

{

background-color:{{ palette.0|lightness:".93"|saturation:".1" }};

}

If you would prefer to serve the CSS statically, then you can always save the rendered version when you are satisfied with the colour scheme. Although calculating the colours dynamically can create some interesting possibilities; you could change your colour scheme depending on the time of day, or allow the user to set the colour scheme in the preferences for example.

Here's the code: djangocolor.zip. The zip contains a couple of Python files that you can drop in to your project; 'colours.py' contains the tags and filters, 'webcolor.py' contains the WebColour class which is independent of Django and could be used in other frameworks.

The code was written rather hastily in an afternoon. I'd kind of like to work on it further and produce a project for it, but I don't have the time at the moment. My hope is that someone will use it for the basis of a more complete colour module that I can use in future projects. The code is released under my politeware license, which means you can use it for whatever purpose you like, as long as you say thanks!

P.S. If you are wondering why I spell colour inconsistently, it's because being British, I naturally spell it with a U, but I spell it without the U in code to be consitent with CSS.

Use Markdown for formatting
*Italic* **Bold** `inline code` Links to [Google](http://www.google.com) > This is a quote > ```python import this ```
your comment will be previewed here
gravatar
Jeff Balogh

This looks pretty cool! I haven't used it yet, but in case I do, thanks.

gravatar
Nick Moffitt

Have you considered using the built-in colorsys module to do your conversions between systems?

gravatar
Will

Nick, I wasn't actually aware of the colorsys module. It would have save me a little time!