CSS Sprites generation tool

June 27th, 2007. Tagged: Ajax, CSS, JavaScript, performance, php

Here's my last weekend's project - a web-based tool to generate images for CSS sprites: http://www.csssprites.com. Cool domain name, eh? I couldn't believe it was not taken.

CSS Spr...what?

This is a simple technique used for page load performance purposes. Since HTTP requests are the most expensive thing you can do in regards to front-end performance, you strive for making as little requests as possible. So instead of having the browser download 4 rounded corner images for example, you create one image that has all four. Then you use CSS' background-position to only show the part of the image you want. More on the subject in this ALA article

How does the tool work

You upload as many images as you want and the tool generates a mosaic of all images, gives you the result as PNG and gives you the coordinates you need to use in the background-position declaration. The tool also gives you an html page as an example, so you can save both the PNG and the html page for reference.

Image size

If you properly optimize the big image, you might actually have smaller size than all the individual images combined. In my tool, the PNG image generated is not optimized at all, I leave this to you to use PNGOUT or any other tool you know. Also you can convert the PNG into GIF if that's better for your purposes.

Implementation - PHP

The PHP code is fairly simple. The actual spriting (is that a word?) class takes a list of images and calls getimagesize() on each one to get the dimensions. The image with the biggest height is used as distance between images. The rest is just composing the imagemagick command that will to the work. Here's the important method:

function combine() {
    if ($this->distance === false) {
        $distance = $this->_biggest;
    } else {
        $distance = (int)$this->distance;
    if ($this->output_dir === false) {
        $output_dir = $this->_dir;
    } else {
        $output_dir = $this->output_dir;
    $half = ceil($distance / 2);
    $coord = array();
    $y = 0;
    foreach ($this->images as $i=>$data) {
        $this->images[$i]['x'] = $half;
        $this->images[$i]['y'] = $half + $y;
        $coord[] = '-page +0+' . $y . ' ' . $i;
        $y += $data[1] + $distance;
    $cmd = 'convert ' . implode(' ', $coord)
         . ' -background none -mosaic -bordercolor none -border '
         . $half . 'x' . $half
         . ' ' . $output_dir . '/result.' . $this->output_format;
    system($cmd, $ret);
    return $ret === 0;

Implementation - JS

In the spirit of web2 I couldn't afford a complete page reload 😆 although it would've been much simpler. I just had to get fancy. YUI to the rescue. On page load I set up the form for async request, using YAHOO.util.Connection. In case of file uploads YUI generates an iframe behind the scenes and uploads to the iframe. Then it takes whatever is in the body on the iframe and gives it to you instead of the XMLHttpRequest's responseText property.

So the files are uploaded to upload.php which calls the class that has the method mentioned above then loops through the $images property of the said class and writes the example html file as well as prints out a JSON string with the same image information.

YUI's Connection calls my callback function and I get the invaluable responseText. Parsing the JSON with the json.js, I get a JS object. Looping through it and DOM-generating a table of results is the semi-last step. The last is (we're fancy, remember?) to yellow-fade the background color of the result, using YAHOO.util.Animation.

BTW, I got fancy once again and combined and minified json.js with my JS file, so that there is one less request and a side effect impossible to read. The unminified version of the JS that does all the work is here for reference.


I hope this tool cane be useful for quickly generating those sprites, if only for prototyping purposes. Any comments, requests, bug reports are all very welcome.

And how do you like the version of the tool? Anyone n00b can do "beta", it takes a true h@x0r (or something) to do a better job 😀

Ah, yeah, and the page badly needs a stylesheet, do you want to help?

Tell your friends about this post on Facebook and Twitter

Sorry, comments disabled and hidden due to excessive spam.

Meanwhile, hit me up on twitter @stoyanstefanov