Skip to main content

Painting with numbers the Sass way.

Written by Hatchd

We’ve been itching to have a play with some of the most underused and elusive Sass functions for a while now: the colour functions. We’ve always known they were around, and up until now we’ve been using the simple lighten, darken and mix to theme sites for quite some time—usually a little like this:

// Step 1: Define the main brand colors in variables, i.e. 
$brand-primary:#ff0000;
// Step 2: Use lighten/darken/mix to adjust colors throughout the site, i.e. 
border:1px solid mix(white,$brand-primary,10%);

But we really wanted to come up with something a tad more robust which would actually create colour schemes, and not just adjust a set colour’s brightness randomly—the idea being that you could pass a function for a brand’s primary colour, and the whole site would be themed based on that colour; think Adobe Kuler but in CSS.

To get started we looked into the actual maths behind the colours (insert witty pun about painting with numbers here), and it seems that there are a number of rules or algorithms that can create colour palettes that are pleasing to the human eye:

  1. Monochromatic
  2. Analogous
  3. Triads
  4. Complementary

Plumping for the complementary path, we took a look at what Smashing Magazine’s Cameron Chapman had to say:

“Complementary schemes are created by combining colors from opposite sides of the color wheel. In their most basic form, these schemes consist of only two colors, but can easily be expanded using tones, tints, and shades.”

— Cameron Chapman, Smashinng Magazine

Example of Hatchd’s main brand colour (in the middle) using a complementary 5 color scheme.

Simple right? To create a colour’s corresponding complementary colour, you simply move over to the opposite side of the colour wheel. In numbers terms, this means just adjusting the colours hue by 180deg. Most web designers will be familiar with the good old CSS ways of representing colours:

    HEX ie. color:#ff0000;
    RGB ie. color:rgb(255,0,0);

Saturation and Lightness, i.e. hsl (100deg,100%,100%); So we knew what we needed—to adjust the Hue of our colour to obtain its complementary counterpart—and we set out on a mission to achieve it: we wanted to be able to convert the hex colours that web designers are familiar working with to HSL so we could adjust the hue by 180deg.

Research showed us the sass functions hue(), saturation() and lightness(), which when passed a hex colour will return the hsl value dependent on which function you use, and armed with this knowledge we proceeded to write a utility function to convert hex to HSL. To make a simple hex-to-hsl function was as easy as:

@function hex2hsl($hex){
    @return hue($hex),saturation($hex),lightness($hex);
}

With that conversion in the bag, we knew we could use this function to get the hue of a hex colour and then adjust it to create complementary colours - when we stumbled across the sass adjust-hue() function, which does exactly what we needed already. Schoolboy error!

With adjust-hue() getting a colours complimentary colour was as easy as adjust-hue($hex,180); It couldn’t get any simpler than that could it? Well yes: the guys at Sass then put us to shame! There was actually a complement () function hidden away already, so shortening the complexity even further was simply a case of using complement($hex); to produce any colour’s complementary colour. This newfound knowledge helped us write the actual the actual complementary scheme function, beginning like this:

@function complementaryScheme($color){
    @return
        $color,
        complement($color)
    ;
}

We can now call the function and pass it a hex colour, and it will return a list including the original colour and its complementary colour. This can then be used in the following way:

$scheme:complementaryScheme(#ff0000);
body {
    background:nth($scheme,1);
    color:nth($scheme,2);
}

We were halfway there. In their most basic form, these complementary colour schemes consist of only two colours, but can easily be expanded using tones, tints, and shades. To use shades—much as Adobe Kuler does—we fell back to the good ol’ mix() function and the completed function took form:

@function complementryScheme($color) {
      $complement:complement($color);
      @return
            mix(black,$color,20%),
            $color,
            mix(white,$color,20%),
            mix(black,$complement,10%),
            mix(black,$complement,20%)
      ;
}

This led us to the discovery that the full complement of the original colour was sometimes a tad jarring. To quote Cameron Chapman again:

“Using colors that are exact opposites with the same chroma and/or value right next to each other can be very jarring visually (they’ll appear to actually vibrate along their border in the most severe uses).”

— Cameron Chapman, Smashing Magazine

Mixing 10% black into the colour helped combat the issue, as did tweaking the amounts of black and white as mixed by eye until we were happy with the outcome.

This function can be really helpful for brands that have no secondary colours, or when creating a site builder that could style an entire website based on a singular chosen colour. Future improvements would ideally see the function returning a map with meaningful key value pairs rather than a simple list.