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
- create image:
$ convert *png *gif -append PNG8:result/result-sprite.png
- get dimensions:
$ identify -format "%g - %f\n" *png *gif
- 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.
Comments? Find me on BlueSky, Mastodon, LinkedIn, Threads, Twitter