Icons, SASS, and styleguides (oh my)

Chris
Skyscanner People
Published in
5 min readOct 9, 2015

Recently I’ve been working on updating Skyscanner’s living styles service with some delicious new icons. The best resources are the ones that people use, and the way that I approached this was from exactly that attitude.

Whilst we don’t use a ton of icons at Skyscanner, it’s still vital that we don’t use the same icon to mean different things. Providing a ‘single source of truth’ as my colleague James Ferguson calls it, means that everyone in the company can source resources from one place.

But how do you balance the need for a single reference (with the benefit of easy updates) with the often prickly nature of icons (easy recolouring, sizing)? Why with good ol’ SASS!

I’ll leave aside the process of generating the icons. Suffice to say that I use Illustrator, warts and all. You may prefer Sketch, or whatever the vector program du jour is. At the end, you want to output SVG files that cover the majority of sizes throughout your product. We’ve gone with 16/24/32, with each size covering the range from its base size up to the next. This means that a single pixel line on an icon will only ever be sized up, not down. Obviously this won’t work on icons below 16px, but I’d question whether you should be showing these on LDPi devices at all below that size.

Once that’s done, it’s time to work out what these icons all have in common. Assuming you’ve gone for a square base grid, each of them should have an identical width and height (taking into account padding). In my case, they’re also all being served as background images, and, strangely enough, I only want one icon to appear. So how about:

@mixin ls-icon($size) {
width: $size + px;
height: $size + px;
background-repeat: no-repeat;
}

That looks pretty good. So for a sample icon, we’d want to put down:

// Icon - General – Calendar

@mixin ls-icon-calendar($size) {
@include ls-icon($size);
}

At this point, if you’re using a single size of icon for all screens, you might want to add in the background image (dataURI’d, natch):

// Icon - General – Calendar

@mixin ls-icon-calendar($size) {
@include ls-icon($size);
background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20fill%3D%22%2334363d%22%3E%3Cpath%20d%3D%22M14%202h-1c0-.6-.4-1-1-1h-1c-.6%200-1%20.4-1%201h-4c0-.6-.4-1-1-1h-1c-.6%200-1%20.4-1%201h-1c-.6%200-1%20.4-1%201v9.6c0%201.3%201.1%202.4%202.4%202.4h9.4c1.2%200%202.3-1%202.3-2.3v-9.7c-.1-.6-.5-1-1.1-1zm0%2010.7c0%20.7-.6%201.3-1.3%201.3h-9.3c-.8%200-1.4-.6-1.4-1.4v-6.6h12v6.7zM3%207h3v3h-3z%22/%3E%3C/g%3E%3C/svg%3E');
}
It is a perfect… icon

So that’s great if we’re serving up a single icon, but not ideal if you want to optimise it for different sizes. As we said at the start, the best resource is one that people use, so we want this to be as easy to use as possible. Remember, it may not be a designer picking this up, so they’re not going to remember to load up ls-icon-calendar-24 rather than -16 or -32.

At this point we can leverage a nice if/else statement in SASS:

// General – Calendar

@mixin ls-icon-calendar($size) {
@include ls-icon($size);

@if $size <= 16 {
background-image: url('');
} @else if $size <= 24 {
background-image: url('');
} @else if $size >24 {
background-image: url('');
}
}

So now we serve the right icon up dependant on the size.

16
24
32

At this point, everything is great apart from one tiny, flaw: color. As Mr Ford said, you can have these in any colour as long as it’s black (or whatever you chose initially).

Or can you? By now you’ve hopefully followed Chris Coyier’s advice and stopped Base64'ing your SVGs. As a result, your inline SVGs should look a little something like this:

data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20fill%3D%22%23000000%22%3E%3Cpath%20d%3D%22M14%202h-1c0-.6-.4-1-1-1h-1c-.6%200-1%20.4-1%201h-4c0-.6-.4-1-1-1h-1c-.6%200-1%20.4-1%201h-1c-.6%200-1%20.4-1%201v9.6c0%201.3%201.1%202.4%202.4%202.4h9.4c1.2%200%202.3-1%202.3-2.3v-9.7c-.1-.6-.5-1-1.1-1zm0%2010.7c0%20.7-.6%201.3-1.3%201.3h-9.3c-.8%200-1.4-.6-1.4-1.4v-6.6h12v6.7zM3%207h3v3h-3z%22/%3E%3C/g%3E%3C/svg%3E

And what’s that right in the middle? Why it’s a (slightly disguised) hex colour (#000000 — %23000000). Being the wonderful little pixie it is, SASS will happily let you chuck a variable in there, as long as it’s done in the right syntax:

background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20fill%3D%22#{$color}%22%3E%3Cpath%20d%3D%22M14%202h-1c0-.6-.4-1-1-1h-1c-.6%200-1%20.4-1%201h-4c0-.6-.4-1-1-1h-1c-.6%200-1%20.4-1%201h-1c-.6%200-1%20.4-1%201v9.6c0%201.3%201.1%202.4%202.4%202.4h9.4c1.2%200%202.3-1%202.3-2.3v-9.7c-.1-.6-.5-1-1.1-1zm0%2010.7c0%20.7-.6%201.3-1.3%201.3h-9.3c-.8%200-1.4-.6-1.4-1.4v-6.6h12v6.7zM3%207h3v3h-3z%22/%3E%3C/g%3E%3C/svg%3E');

The bit you’re looking for is #{$color}, which replaces the %23 and the six digit hex value.

This now means we can write our icon mixin like this (I’ve removed the dataURIs for clarity):

// General – Calendar

@mixin ls-icon-calendar($size, $color) {
@include ls-icon($size);

@if $size <= 16 {
background-image: url('');
} @else if $size <= 24 {
background-image: url('');
} @else if $size >24 {
background-image: url('');
}
}

and include them like this:

.calendar-icon {
@include ls-icon-calendar(16, #34363d);
}

Which eventually gives us:

.calendar-icon {
width: 16px;
height: 16px;
background-repeat: no-repeat;
background-image: url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20fill%3D%22#34363d%22%3E%3Cpath%20d%3D%22M14%202h-1c0-.6-.4-1-1-1h-1c-.6%200-1%20.4-1%201h-4c0-.6-.4-1-1-1h-1c-.6%200-1%20.4-1%201h-1c-.6%200-1%20.4-1%201v9.6c0%201.3%201.1%202.4%202.4%202.4h9.4c1.2%200%202.3-1%202.3-2.3v-9.7c-.1-.6-.5-1-1.1-1zm0%2010.7c0%20.7-.6%201.3-1.3%201.3h-9.3c-.8%200-1.4-.6-1.4-1.4v-6.6h12v6.7zM3%207h3v3h-3z%22/%3E%3C/g%3E%3C/svg%3E"); }

Which, I think you’ll agree, is pretty nifty.

I’d love to hear if you’ve got any clever additions, suggestions, or criticisms of this. It seems to work pretty well for us so far, but I’m always happy to improve.

--

--

Chris
Skyscanner People

Design Lead at Kaluza. All writing is my own views.