Practically Sass-y: CSS Sprites

This is a repost of an article I wrote for the K-State OME web team blog.

Sometimes I can end up being a little too dogmatic when I approach building new designs, especially when I become overly focused in certain areas. Recently, I became a little obsessed with reducing HTTP requests and page weight while implementing a cool, new design.

The design was a single, vertically-scrolling page, and was pretty graphically intensive, all of which was starting to weigh down the page. After the page was built, I was looking at over 34 HTTP requests and a little more than 5 MB page weight. Certainly not ideal for many pages, let alone a vertical-scrolling page. The answer to reduce most these requests was obviously to use CSS sprites.

I’ll skip over the importance of reducing HTTP requests for page speed, and just talk about how to easily accomplish it using SpriteMe and Sass.

I’ve put together sprites before, but never one with this many images, let alone while the design was organically changing. The answer to this problem was to follow the workflow that Chris Coyier outlines in his CSS Sprites Workflow post.

To summarize, he suggests not making any sprites at the beginning, reference each background image separately in the CSS with the background shorthand property, use SpriteMe to create your sprite(s), and comment out the separate background property when you add the sprite. (You should really read his post, he explains it far better than I do.)

A solid workflow, indeed. Once I added Sass into it, it became even better.

I created a mixin that looked like this:

@mixin content-pre-sprite($img, $x, $y, $height, $width)
    background: transparent url($img) no-repeat $x $y
    height: $height
    width: $width

Which was added to every element that needed a background-image, like so:

h1
     @include content-pre-sprite('../images/originals/event-details.png', -9px, -6px, 144px, 372px)

After the sprite was made, I created a new mixin:

@mixin content-sprite($x, $y, $height, $width)
    background: transparent url(../images/content-sprite.png) no-repeat $x $y
    height: $height
    width: $width

Which was added to each respective element like this:

h1
     @include content-sprite(-19px, -316px, 144px, 372px)
     // @include content-pre-sprite('../images/originals/event-details.png', -9px, -6px, 144px, 372px)

Chris’s post says not to worry about extra code being served up with your CSS because of the comments, because it will most likely be compressed anyway. That is true, but with Sass, single-line comments aren’t outputted to the compiled CSS anyway, so you really don’t have to worry about it.

For the curious, the compressed, compiled output for that element would end up as:

h1{background:transparent url(../images/content-sprite.png) no-repeat -19px -316px;height:144px;width:372px}

Sure, repeating the same values across several elements might not be the most efficient use of CSS, but overall it wouldn't be much less efficient than declaring each background-position. I can live with a little less code efficiency, if it promotes a more efficient workflow. Unfortunately, I cemented this workflow after I'd done some things the hard way, so hopefully you can learn from my mistake.

Better yet, if you use Compass you can get it to do most of the work for you. Spriting in Compass, which is based on Lemonade, looks extremely useful. I haven't tried it out yet, but I'd like to in the very near future.

Oh, and that vertically-scrolling page? That's currently sitting at 24 HTTP requests (which I could probably reduce further) and a little over 1 MB page weight. I can certainly live with that. To be clear, the majority of the weight loss was from good image compression; however, the request reductions were a result of using sprites – meanwhile other things were also added.

TL;DR

CSS sprites are useful in reducing HTTP requests. Using SpriteMe and Sass, you can easily integrate sprites into a new/changing design.