So you’ve got your sprite created, and it’s working great. 30+ icons in one image… major HTTP connections saved. You have made your little corner of the interwebs a little happier and faster. Steve Souders would be proud.
Until you find that your sprite is used on an element that is tall enough to expose the next image component down in the sprite. The 50px of spacing between components you thought would be enough… isn’t. 50px isn’t enough so 100px should be right? Better make it 200px to be ultra safe. So you increase the space between all of your components from 50px to 200px which increases the height by 400% and probably increases the filesize a bit too.
The 200px spacing surely is tall enough… right? RIGHT??!? Surely no content maintainer would ever put more then 200px of content in there after you hand it off. *gulp*
I figured there had to be a better way to make sure this didn’t happen. Horizontally spacing the sprite would solve the too tall issue, but then it has to be spaced out pretty decently as well. Probably even more than the vertical spacing. What I wanted was the best of both worlds. Horizontal AND vertical spacing.
What do you get when you both horizontally and vertically space something? A diagonal. I searched around but couldn’t find any mention of a diagonal sprite. I didn’t know if that meant this was a new idea, or a bad one that no one was willing to publish. I’m hoping it’s the former.
Why a Diagonal Sprite?
With the sprite built on a diagonal there are no components below or to the right of the component you are showing. This allows for the element using the sprite to be as wide or as tall as it needs to be with no worry of exposing the next component.
Unfortunately there is a filesize tradeoff. You add a LOT of unused whitespace. For one 30 or so component sprite that I changed from vertically stacked to diagonally stacked, there was only about a 10% increase in size. For another that had around 60 images, it was a 45% increase. The 10% increase was pretty easy to swallow for the benefit gained. The 45% is a bit harder. So your mileage may vary.
Since you don’t have to put as much spacing between your sprite components (I do 10px vertically and horizontally to allow a little per component manipulation) the sprite dimensions are significantly smaller. My 60 sprite image with 50px of space between components was 2142px tall. Spacing it out to 200px between components took it to over 8000px. The diagonal sprite using the same 60 components, with 10px padding ends up being around 1500px tall and wide. As far as I can tell this only really matters to the Opera browser. I can’t find information on any other browser having issues with ginormous dimensions, but would love to hear feedback if you know of other issues.
So that you can see this in practice, I created a simple 10 component sprite from a few icons from the famfamfam silk icon set (seen above). You can view an example page that shows the 50px, 200px and diagonally spaced sprites. The filesizes and dimensions ended up being: 50px – 16×610 5,723 bytes, 200px – 16×1960 5,967 bytes, diagonal – 250×250 6,554 bytes.
Resize the page to be fairly narrow to get content to wrap and even the 200px spaced sprite exposes an additional component.
Making the Diagonal Sprite
When making my normal vertically stacked sprites I use the fantastic online tool CSS Sprite Generator. I noticed that the back end for that was open source and so grabbed a copy.
After significant pain in getting the required components installed on my local machine (post on that coming later), I tweaked their code to output the sprite in a diagonal. At the moment the code is kind of quick and dirty since I wasn’t sure if it was going to work. If there is interest in me making it available, please let me know in the comments below and I’ll try to get it cleaned up and released.
In the end I think this is a pretty decent solution to the problem I ran into. It probably doesn’t work for everyone and the filesize increase is something to consider, but it is an interesting option to have in the back pocket. I would love to hear your thoughts on this solution.