Using SASS with sprites

The SASS preprocessor promises to take much of the grunt work out of developing CSS. Lengthy, repetitive spriting code would especially benefit from this.

Why sprites?

It has become a best practice in web development to combine multiple small iconic images into a single image called a sprite. CSS is used to ensure only the desired image within the sprite is displayed in any given context. When deployed, the benefit is far fewer HTTP requests as the page renders, which results in improved performance.

Managing the CSS

There are various ways to specify the CSS. For icons, bullets, and other “decorative” elements, I prefer to use the :before pseudo element. A typical call to a sprited image looks something like this:

div.errorsummary.basic:before {
  content: "";
  position: absolute;
  background-image: url("../images/icons-01-20130705.png");
  background-repeat: no-repeat;
  background-position: -20px 0;
  width: 14px;
  height: 14px;
  top: 5px;
  left: 4px;
}

That’s a lot of code, but it can be greatly simplified by following the standard practice of moving all the repeating rules into a single combined selector, then, on the individual selectors, declaring only those rules that are specific to that selector. Here’s how that might look.

First, set up the sprite for all the selectors that call it.

div.errorsummary.basic:before, a.arrow:before [etc] {
  content: "";
  position: absolute;
  background-image: url("../images/icons-01-20130705.png");
  background-repeat: no-repeat;
}

Then, for each selector, specify the background position, dimensions, and position:

div.errorsummary.basic:before {
  background-position: -20px 0;
  width: 14px;
  height: 14px;
  top: 5px;
  left: 4px;
}

Note that the sprite only gets called once. If you’re aggressively caching all images – and you should be, for performance – you should rename this file every time you change it.

Enter SASS

The main contributions SASS makes to this process are modularising the code, and greatly streamlining the specifications of each image within the sprite.

The first step is to recognise that, while every image may be deployed in different contexts, the actual specification of the image relative to the sprite – its background-position, width, and height – will remain unchanged. Therefore, following the principle of DRY (Don’t Repeat Yourself), it makes sense to separate out these specifications in a reusable form. When you come to create the actual CSS declarations, you can refer to each image in the abstract, leaving you with just the top and left rules to write.

Using SASS syntax, here’s how a simple sprite comprising four images might be specified:

$icon-windows:
  (error-icon-basic, background-position (-20px 0),
    width 14px, height 14px)
  (error-icon-verbose, background-position (0 0),
    border (1px solid red), width 20px, height 20px)
  (arrow-up-white, background-position (-50px -10px),
    width 10px, height 10px)
  (arrow-up-blue, background-position (-70px -10px),
    width 10px, height 10px)
;

Don’t worry about the peculiar syntax for a moment (more about that below), just note that, for instance, your icon for a verbose error message has its key rules listed here, and can henceforth be called by its shorthand name, error-icon-verbose.

To place these icons within selectors, you need a second list comprising the position declarations. Using similar syntax, it will look something like this:

$icon-positions-before:
  (nav-a, top 22px, left 43%)
  (nav-a-hover, top 21px, left 43%)
  (errorsummary-basic, top 5px, left 4px)
  (errorsummary-verbose, top 40%, left 0)
  (backtotop-a, top 2px, left 2px)
;

Now you have a second set of shorthand names, each describing a context in which an icon will be used.

With that out of the way, you call the sprite itself via the combined selector above, then use the following include call inside the individual selector:

@include icon('error-icon-verbose', 'errorsummary-verbose');

The icon mixin is listed in the Downloads, below. The first argument is the shorthand for the icon, the second the shorthand for the context. There’s an optional third argument, which refers to the position of the icon relative to the element. As most icons are at the beginning of the element, this defaults to ’before’. If you specify ’after’, then the pseudo-element will be ’:after’, and the position rules will change accordingly. For flexibility, you will then need another list of position declarations called $icon-positions-after. This allows you to repeat the shorthands for the context, and keeps large sets of sprite specifications neater and more self-documenting.

Alternatives

My first version of this used the very convenient placeholder selector (%). Instead of the above lists, I had more intuitive lists of selectors, e.g.

%error-icon-basic	{background-position: -20px 0;}
%error-icon-verbose	{background-position: 0 0;}

These work like regular selectors, except that they don't appear in your CSS. Instead, their purpose is to extend other selectors. This approach ran aground when I tried to integrate it into a mobile-first RWD context. Because of how @extend works, SASS will throw a deprecation warning if you try to extend a selector inside a media query when the original selector is outside the media query. I know of no workaround, and there's no likelihood that this restriction will be relaxed: this deprecation warning is set to become an error in the next version of SASS (3.3). I liked the simplicity of this approach, although I wasn't so happy about specifying each image via a selector, even an "invisible" placeholder selector.

I also tried Compass’s sprite generation capabilities, but I found it a little clunky and inflexible. I love the idea of dropping individual images into a folder, and having Compass stitch them together and generate the code, but for my needs, it was quicker to just write my own code. The “sprite stitching” capability sure would have been nice, though.

Other considerations

A word about that list syntax. At a glance, it looks like an error-ridden dialect of PHP, but it’s SASS’s way of managing multidimensional lists. Each outer parenthesised group is a list element, which in turn contains another list, separated by commas. Where an inner item contains spaces, that item must also be parenthesised to avoid ambiguity.

This syntax is somewhat crude and clumsy, but it’s clear from browsing the SASS issues queue that the language is still in its infancy, and that key concepts are still being worked out. Unless future browser capabilities make SASS moot, I foresee a mature version of SASS having all the key data constructs of regular computer languages. For instance, it appears that the next version of SASS, 3.3, will have a map data type, which seems roughly analogous to an associative array.

Additional tips

Although actually creating the sprite in your image editing program is beyond the scope of this post, one tip I’d offer is to set up a grid of 10 pixel by 10 pixel units, and “snap” your images to these units. Don’t worry about the left over spaces. Performance zealots will quibble at the slight image bloat that results, but it’s negligible in comparison with the convenience of managing background position rules in multiples of 10 pixels.

Downloads

Download the example code, including all necessary mixins.

Posted in:

comments powered by Disqus