Adventures in theming

— 5 minute read

Using products like Twitter and Trello every day, I've long appreciated the importance of making my regular online tools feel like home. Luckily since Progression's inception we've allowed teams to enter a hex value as their brand colour. We just never really used them (which thinking about it must have been pretty underwhelming).

Well this week I did one of my classic 'not on the roadmap' evening hacks, and decided to spend an hour or two seeing how hard it would be to add theming into our app.

It would turn out to be an interesting journey of discovery with a lot of 'today I learned' moments.

Not all colour spaces are created equal. permalink

Everyone understands HEX (i.e. #ff0000). And in fact most understand RGB too – three numbers from 0-255 corresponding to Red Green and Blue. HSL is the lesser known cousin, but by far the most powerful of the colour spaces.

HSL stands for Hue, Saturation and Lightness. Hue is measured as a 360° colour wheel and saturation and lightness are 0-100%. What's great though is that having lightness and saturation allow you to manipulate a colour programatically in a really easy way without affecting the important one for most, the hue. And Hue being seperate means you can programattically find complimentary colours by just subtracting an 'angle' from your hue value.

So, a worked example. If I have an HSL colour of 145°,44%,81% I can decide to spit out complimentary colours by changing the Hue, shades of the same colour using the lightness and I can also avoid some of the crazy combinations that make UI unusable by controlling saturation. All just with maths. 🤯

Fun with HSL
Fun with HSL

I didn't know that when asking people for a HEX code as their brand colour, but to be fair asking for an HSL would have resulted in mainly confusion anyway. Luckily CSS Tricks has some great articles on converting colour spaces which came in handy.

Sass renders before grabbing css variables permalink

I had initially hoped to keep my lighten() darken() and color-scale() sass manipulators with my new colours.

However, it turned out that when sass precompiles your css it doesn't know anything about those variable syet. It's just moving the string around, not looking into it. So trying to darken a string is obviously not going to work.

I was going to have to create all my variables as css variables for my theme colours and just reference them in sass.

Getting variables from our database and turning them into arrays of css variables. permalink

Usually you would create css variables with a style tag. However it quickly became apparent that as I was using js to manipulate the styles anyway, having a script tag (to manipulate) inside a style tag (to set variables) felt.. icky.

But hooray, you can set css variables with javascript. This became my friend. I ended up creating a json route in the app that was hit on page load, pulling in the hex (or a fallback) which I would then pass through my js to create my HSL values. Then it was just a case of running all variants through this command to create my variables.

getComputedStyle(document.documentElement)
    .getPropertyValue('--my-variable-name'); // #999999

People have some weird brand colours permalink

All my colours in a row
All my colours in a row

OK so all well and good, I spat out the brand colour and then created an array of different lightnesses. Then in my variables.scss I created variables from my variables.

Working through my templates, it was easy to grep $brand-color and swap out with $theme-color (or $theme-color-10, 20, 30 etc. as I went along. What I didn't anticipate was how weird some teams' brand colours would be.

Very quickly on rolling out the theming we found some examples of borderline unusable UIs because some colours which look normal are actually pretty weirdly constructed (for example if saturation is really high and lightness is low, the colour looks muted. As soon as you drop that lightness, shit gets crazy).

So the final step was to block super high saturation. I chose to limit saturation to 60 with a (s>60?60:s) on incoming saturation value. That's good enough for now.

Future improvements permalink

  1. We're thinking of adding a package like color so we can detect luminosity. Only then will we be able to avoid accessibility issues and strange UI's.
  2. Frankly, the number of elements we've applied this to may be overkill. If it feels too much we may pull it back a bit, but for now it feels cool to have your Progression UI look like yours.

The team page with a red look
The team page with a red look

Your organisation homepage
Your organisation homepage

Simple theme options for now
Simple theme options for now


Enjoying these posts? Got any feedback? Feel free to email us at team@progressionapp.com.


Posted by Jonny in