# Compass and CSS Sprites, Explained Last week I attempted to use the [CSS sprites feature](http://compass-style.org/reference/compass/helpers/sprites/) of Compass for the second or third time. It's been a struggle each time, but the power and potential is there, so I keep coming back. This time was a bit different, though, because I finally decided to stop relying on the docs and dive into the code. Before I go into the nitty-gritty, let's take a step back and talk about why I want so badly to use this feature and why it's been painful each time. The why is easy: CSS sprites significantly reduce HTTP requests, and manually building sprite maps and calculating sprite positions is a pain in the ass. If I'm going to use sprites, it has to be done in an automated fashion. Since I'm already using Compass, and Compass has CSS spriting built-in, it seems a no-brainer. This is a feature I need to be using. Unfortunately, [the docs](http://compass-style.org/help/tutorials/spriting/) leave much to be desired. You might read those docs and be convinced that the "right" way to use CSS Sprites is with magically-generated CSS classes applied to your markup. Not so. There is a better way to use sprites that is more straightforward, easy to understand, and without future developers having to understand magically generated mixins and classes. To get there, let's dive into the code that makes the "magic" classes work. [This template](https://github.com/chriseppstein/compass/blob/stable/lib/compass/sprite_importer/content.erb) is where all of those magic mixins are defined when you import your sprites with something like `@import "my-icons/*.png"`. You can see that these generated mixins are straighforward and in most cases are just delegating to a regular mixin defined [here](https://github.com/chriseppstein/compass/blob/stable/frameworks/compass/stylesheets/compass/utilities/sprites/_base.scss). While not documented, there is no reason we can't use those mixins ourselves. Let's say you want to apply a background image called "ribbonfull.png" to your `h3` tags. Following the docs, your code might look like this: ```sass @import "spritemap/*.png" +all-spritemap-sprites ``` ```html

Test

``` Let's turn that into something more maintainable and customizable. Under the covers, the "spritemap-ribbonfull" class is really just applying a couple mixins. We can do the exact same thing with this: ```sass @import "spritemap/*.png" h3 background: $spritemap-sprites no-repeat +sprite($spritemap-sprites, ribbonfull) ``` The only bit of magic left is the generated `$spritemap-sprites` variable. I can live with that. We no longer have to change our markup, and we can customize how the background image is applied by supplying additional arguments to the [sprite mixin](https://github.com/chriseppstein/compass/blob/stable/frameworks/compass/stylesheets/compass/utilities/sprites/_base.scss#L27). In my recent project, I took this a bit further by defining my own mixin. ```sass $spritemap-spacing: 50px @import "spritemap/*.png" =background-sprite($name, $repeat: no-repeat, $offset-x: 0, $offset-y: 0) background-image: $spritemap-sprites background-repeat: $repeat +sprite-background-position($spritemap-sprites, $name, $offset-x, $offset-y) // if no offsets given, set the dimensions of the element to match the image @if $offset-x == 0 and $offset-y == 0 +sprite-dimensions($spritemap-sprites, $name) ``` By writing my own mixin, I not only have more control over how the sprites are used, but future developers can read this mixin and understand what is happening. Here is how I'm using it: ```sass // simplest case; sets the background image and dimensions of the element h3 +background-sprite(ribbonfull) // custom offset; does not set the dimensions of the element h2 +background-sprite(ribbonend, no-repeat, 3px, 22px) // repeating backgrounds are possible, too #positions +background-sprite(doubleline, repeat-x, 0, 45px) ``` The generated CSS looks this: ```css h3 { background-image: url('/images/spritemap-sb826ca2aba.png'); background-repeat: no-repeat; background-position: 0 -405px; height: 29px; width: 295px; } h2 { background-image: url('/images/spritemap-sb826ca2aba.png'); background-repeat: no-repeat; background-position: 3px -296px; } #positions { background-image: url('/images/spritemap-sb826ca2aba.png'); background-repeat: repeat-x; background-position: 0 -751px; } ``` There are a few gotchas worth mentioning whenever you're using sprites. First, unless every background image is oriented at the top left and fills the full element, you're going to want some spacing between the sprites so adjacent images don't sneak in. Play with the `$-spacing` configuration variable to see what works for you. I ended up at 50px. The other gotcha is with repeating backgrounds. By default, Compass will stack the images veritically in the sprite map. This means you can still have repeating backgrounds on the x-axis, but you'll need to ensure that any image you want to repeat is the fill width of the generated sprite map. Images that repeat on both axes (such as background textures) are not possible with sprites. I'm pretty happy with how this has ended up. I'll definitely be using this feature of Compass in most future projects. CSS Sprites are a powerful way to increase browser performance, and now there's less friction than ever to give it a try.