Command-line CSS spriting

February 19th, 2011. Tagged: CSS, images, smush.it

(In Russian)

OK, CSS sprite tools exist. I'm pretty confident I actually made the very first one 🙂 But they break from time to time (like mine currently). And then the command line is cool (as opposed to scary) and oh-so-quick. And imagemagick is cool and oh-so-powerful. So let's see how we can create CSS sprites from the command line alone.

Creating the image

Starting with a list of separate image files:

$ ls 
1.png  2.gif  dot.png  phoney.gif  tw.gif
  • - 1.png
  • - 2.gif
  • - dot.png
  • - phoney.gif
  • - tw.gif

Creating the sprite:

$ convert *png *gif -append result/result-sprite.png

Yes, that's all! The result:

What?

So the imagemagick command is generally something like:

$ convert image1.png image2.png image3.png -append result/result-sprite.png

But we can also replace the list of images with *s:

$ convert * -append result-sprite.png

Or as in the previous case, limiting to *.gif and *.png.

How about a horizontal sprite? All it takes is changing -append to +append:

$ convert *png *gif +append result/result-sprite-horizon.png

The result:

Also note how the source images can be any format - GIF, PNG, JPEG and the result is PNG. Actually I'd recommend always trying PNG8 first:

$ convert *png *gif -append PNG8:result/result-sprite-horizon.png

CSS positions

Now since this is all hand-made there's no auto-generation of CSS. But it's still pretty straightforward. Take the vertical sprite:

All images will have background-position-x of 0px, so that's easy.

The first image will also have Y-position 0px. It also happens to be 16x16 pixels. So it's:

.first {
  width: 16px;
  height: 16px;
  background: url(result/result-sprite.png) 0 0;
}

... where 0 0 position is redundant and can be omitted.

The second image is also 16x16, that's convenient. Its X is 0 and its Y is the height of the previous image (16px) with a minus in front. So:

.secondo {
  width: 16px;
  height: 16px;
  background: url(result/result-sprite.png) 0 -16px;
}

And so on. Y position of an image is Y of the previous + the height of the previous.

You can use the handy-dandy test page to play around with this (or any other) sprite.

But.. but... figuring out dimensions by keeping track of heights? You kiddin' me?

Imagemagick to the rescue. `identify` gives you the basic image info:

$ identify 1.png 
1.png PNG 16x16 16x16+0+0 DirectClass 8-bit 260b

`identify` also has a `-format` option and supports *. So getting all the info in a neat form is easy:

$ identify -format "%g - %f\n" *
16x16+0+0 - 1.png
16x16+0+0 - 2.gif
6x6+0+0 - dot.png
10x16+0+0 - phoney.gif
16x16+0+0 - tw.gif

%f is filename and %g is geometry.
\n is a new line as you would expect and sometimes - is just a -.
So if you want to figure out the Y position of the fifth element, well, it's the sum of the heights of the previous: 16+16+6+16

.last {
  width: 16px;
  height: 16px;
  background: url(result-sprite.png) 0 -54px
}

Some complicated math! 'scuse me while I ask my second grader if she can handle it 🙂

And some smushing

Imagemagick doesn't write optimal PNGs. So some optimization is due. You can do it yourself with pngout, optipng, etc. Or use web-based tools such as smush.it (you're welcome!) or punypng.com. (psst - how bout a glimpse of the past)

Or how about.... smush.it on the command line:

$ curl http://www.smushit.com/ysmush.it/ws.php
       ?img=https://www.phpied.com/files/sprt/result/result-sprite.png

Result is JSON:

{"src":"https:\/\/www.phpied.com\/files\/sprt\/result\/result-sprite.png",
 "src_size":1759,
 "dest":"http:\/\/smushit.zenfs.com\/results\/5a737623\/smush\/%2Ffiles%2Fsprt%2Fresult%2Fresult-sprite.png",
 "dest_size":1052,
 "percent":"40.19",
 "id":""}

Oh looky, almost half the filesize. Let me at it! Copy the `dest` URL:

$ curl http:\/\/smushit.zenfs.com\/results\/5a737623\/
       smush\/%2Ffiles%2Fsprt%2Fresult%2Fresult-sprite.png > result/smushed-sprite.png

And that's that.

Recap

  1. create image:
    $ convert *png *gif -append PNG8:result/result-sprite.png
  2. get dimensions:
    $ identify -format "%g - %f\n" *png *gif
    
  3. optimize:
    $ curl http://www.smushit.com/ysmush.it/ws.php?img=http://url...
    

Test page to play with the result-sprite is here.

For some more ideas and a different imagemagick command for generating sprites - see the very original post announcing the csssprites.com.

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