Making sprites

So you have a website that uses dozens of little images to make the interface more attractive. Maybe there’s a toolbar or menu, where each item or button has its own icon. It looks great, but it’s a pain to load – each image is a small file and the browser frantically struggles to manage the 20 or 30 requests for all the graphical nicety. The interface feels sluggish. Users get bored and leave. Civilisational collapse soon ensues.

Fortunately, you know how to fix the problem with the use of the great technique of CSS Sprites. If you don’t, you should. Click the link and learn about it; I will assume that you know what CSS sprites are from here on… Yes, CSS sprites are great, but they are a pain to create manually. Not only you need to stitch the images together but also there will be lots of CSS rules to position the background image correctly. Automation comes to the rescue in the form of the montage command (part of the fantastic ImageMagick collection of image-manipulation software goodness) and some quick script hacking…

Creating the sprite

This little tip will create a sprite off a directory of image files with identical size (in this case, 16×16 icons), each one named something sensible. The objective is to get one image file and a bunch of CSS rules built automatically. First, ensure that you have ImageMagick. In Ubuntu this command will do the trick:

sudo apt-get install imagemagick

There are also downloadable distributions for Windows and Mac. Once you’re ready, open a command prompt and go to the folder where your images live, and run this command:

montage *.png -alpha on -background "#ffffff00" -tile x1 -geometry 16x16 ../sprites.png

This will create a file, sprites.png, in the parent folder (in Windows, make sure that you type “..sprites.png” as the last parameter – notice the backslash), with all the images tiled side-by-side. If you require the images to be tiled top-to-bottom substitute -tile x1 with -tile 1x. And if your images are a different size than 16×16, specify that in the -geometry parameter. And if your source images are not PNGs, replace “*.png” as appropriate. I recommend that you open the sprites.png file in your editor of choice and perform any conversions or optimisations as you see fit. Don’t forget to apply OptiPNG if you use PNG as your final format (why wouldn’t you?) to get a really small final file size. Your sprites file will look a bit like this (icons off the excellent Silk Icons set):

Example of icons in sprite file

That takes care of the sprite image. Now for the CSS rules.

Auto-generating CSS rules

We’ll be defining a couple of base rules that apply to all elements (note the references to 16px, the size of the icons; adjust as necessary):

.i16:before, .i16 span {
    content: "";
    background-image: url("sprites.png");
    background-repeat: no-repeat;
    padding: 0 0 0 16px;
    margin: 0 0.25em 0 0;
    *zoom: 1;  /* For IE 6 and 7 */
}

.i16block {
    display: block;
    margin: 0 0 0 16px;
    padding: 0 0 0 0.25em;
    position: relative;
    *zoom: 1;  /* For IE 6 and 7 */
}

.i16block span {
    background-image: url("sprites.png");
    background-repeat: no-repeat;
    height: 16px;
    left: -16px;
    min-height: 1em;
    position: absolute;
    top: 0.115em;
    width: 16px;
}

And one more rule per image, which provides the correct background position. The objective is to be able to use classes like this (in this case, to obtain the PDF icon):

<a class="i16 i16pdf" href="example.pdf">PDF link</a>

Or, for links that might span multiple lines and require nice text alignment (or for IE6 support) we need an extra element:

<a class="i16block i16pdf" href="example.pdf"><span></span>PDF link</a>

First, we need to get a list of files in the directory. Each file will produce a rule, and it is important that the contents of the directory haven’t changed since the sprite was created (this is why we placed the sprite in the parent directory). So, drop to the command line and, in Linux, run this:

ls -1 *.png > filelist.txt

Or, in Windows:

dir /b *.png > filelist.txt

Now we only need a quick script to output a bunch of CSS rules. This can be done with your favourite programming language, but here is an example in Python:

rules = ""
f = open('filelist.txt', 'r')
x = 0
for name in f:
    rules = rules + ".i16Mime" + name[0].capitalize() + name[1:] + ":before"
    rules = rules + ", .i16Mime" +  name[0].capitalize() + name[1:]"
    rules = rules + " span {n    background-position: -" + str(x) + "px 50%;n}nn"
    x = x + 16
f.close()
f = open('rules.css', 'w')
f.write(rules)
f.close()

The above code can be saved as a Python script file (say, “myscript.py”) in the same directory as the images, and run from the command-line like so:

python myscript.py

This will generate a new CSS file, “rules.css”, with all the correct rules for all the icons. It should be pretty easy to rewrite the above in your language of choice (PHP, Ruby, Assembler…)   Simple apply to your links the appropriate “i16 i16type” class names and you should be good to go.

One thought on “Making sprites

  1. Richard

    Great article, love the idea and implementation.

    Your next challenge, should you choose to accept it is:

    * Create a website that you can upload as many PNGs to as possible.
    * Stitch them together in a grid of x by x (determined by biggest sprite) using gd or your weapon of choice
    * Run it through OptiPNG
    * Create the CSS including an option to encode the PNG as a data uri within the CSS itself

    Seems to be a big hole in the market for something like that, I was just looking for something myself and couldn’t find it.

    Rich

    Reply

Leave a Reply