Managing relationships between colours with Sass

Almost all web projects I work on use a CSS pre-processor and of one of the main advantages of using one is the ability to use variables. Colours, hex or codes or otherwise, are usually one of the first pieces of repetitive code to be abstracted into variables because they’re hard to remember; when you’re trying to get stuff done you don’t want to keep looking up 6 character references, hues or luminosities.

In many of the Sass or LESS projects I’ve worked on a second layer of abstraction is also added to map the colour palette to variables which better describe their uses in an effort to avoid the potential pitfalls of being too specific:

// Neutral color palette
$palette-neutral--xdark:  #2C3643;
$palette-neutral--dark:   #3B444F;
$palette-neutral--base:   #67747C;
$palette-neutral--light:  #99A9B3;
$palette-neutral--xlight: #DBE6EC;

// Primary color palette
$palette-blue--dark:      #1D508D;
$palette-blue--base:      #206FAC;
$palette-blue--light:     #288AD6;
$palette-red:             #FA5E5B;
$palette-green:           #16C98D;
$palette-orange:          #FFC83F;
$palette-yellow:          #FEEF6D;

// Color uses
$color-bg:                $palette-neutral--xlight;
$color-text:              $palette-neutral--xdark;
$color-nav:               $palette-blue--dark;
$color-nav--hover:        $palette-blue--base;
$color-link:              $palette-blue--base;
$color-link--hover:       $palette-blue--light;
$color-contrast--bg:      $palette-neutral--dark;
$color-contrast--text:    white;

Usually these two steps are as far as project colour management goes, there are arguably nicer ways of doing it (and smart ways for large, tonal palettes) but the basic conventions suit many cases.

I think colour management can go one step further and specify the relationship between colours, a process which I call themes. The implementation of the themes idea has been made very simple with the release of Sass 3.3 which introduced the Map data structure and associated functions. Themes are just a maps defining a name and the associated colours:

// Themes
$themes: (
  'brand': (
    'primary': $palette-blue--base,
    'secondary': $palette-blue--dark,
    'contrast': white
  ),
  'highlight': (
    'primary': $palette-yellow,
    'secondary': $palette-orange,
    'contrast': $palette-neutral--dark
  ),
  'neutral': (
    'primary': $palette-neutral--light,
    'secondary': $palette-neutral--xlight,
    'contrast': $palette-neutral--xdark
  )
);

My original implementation of the themes idea was for a site which used different arrangements of the colour palette for different sections of the site but I think it’s a useful technique to use on any project, the majority of which will use multiple colour variations for basic elements and components.

A screenshot of the web styleguide at Lonely Planet

At Lonely Planet many of our components come in a variety of colour variations.

A client’s brand guidelines or your team’s designer will always tell you that only certain colours should be used together, a predominant colour will often have a complimentary and contrasting colour. Defining these rules in one place not only prevents duplication throughout the codebase but aids a common language between designers and developers. The single point of reference means non-developers can easily jump in and confidently make tweaks.

The aspect of this technique which really appeals to me though is that it can keep stylesheets really DRY which should aid maintainability in future. For example, simple text variations can be defined dynamically:

// Text color variations
@each $name, $theme in $themes {
  .text--#{$name} {
    color: map-get($theme, 'primary');
  }
}

And variations for more complicated, stateful components can be kept really terse without creating stylesheets that lose coherency:

// Button base
.btn {
  padding: 10px 16px;
  border-radius: 4px;
}

// Button color variations
@each $name, $theme in $themes {
  .btn--#{$name} {
    color: map-get($theme, 'contrast');
    background: map-get($theme, 'primary');

    &:hover {
      background: map-get($theme, 'secondary');
    }
  }
}

CSS pre-processors can make working with colours much easier over the lifetime of a project and this is just another little technique that takes advantage of the extra power. Let me know what you think about defining the relationships between colours in the comments below or check out an example.

View the demo on SassMeister

comments powered by Disqus

A photo of Matt Hinchliffe

About Me

I'm a 29 year old web developer building new stuff at the Financial Times based in London. I specialise in crafting scalable, performance-driven code, tackle accessibility issues and keep an opinionated interest in the latest hotness. I like my tea robustly brewed, white and with no sugar, thanks!