04 December 2007

PNGs - One Image To Rule The Navbar

Graphics for the navigation bar take up 181 bytes of space
A realization struck me today. With PNG files, I can create one tiny image for an entire navigation bar, including mouseovers. Specifically, I was thinking how often I only want to change a color on mouse-over, which has normally meant a separate image, but no more. And it gets better... using this one image method, I can even dynamically change the color of the "image" with CSS or Javascript if I need to. Did I mention it's cross-browser compatible?

The One Image Way

A lot of folks tired of dealing with the tedium of image-based navigation buttons are probably already using the tileable background approach. This is where you create a small sliver of a background and repeat it in the x direction (for horizontal navigation bars), and place your text-based links on top. One Image takes that a step further.

Create the tileable background, but design the image with a solid background color and layer your effects on top of it rather than integrating blends and gloss into the background. Then delete the background color and save only the effects. (This takes some practice if you're not used to it.) Then, in the CSS background property, specify the image as well as the background color, like so:


...
background: #000 url(menu-fx.png) repeat-x ;
...


Now, if you want to change the hover, use the same background image, but only change the color:


...
background: #025 url(menu-fx.png) repeat-x ;
...


Working Example

To see an example of this in action, check out this page. The total amount of space taken up by graphics for this navigation bar is 181 bytes! And I can change the color at design time without saving out a new image (by specifying a different color in the CSS). And I can even change it dynamically with client-side script. If I do have to make changes to the shading or lighting, I only have to save down 1 file, not one file for every color.

Why It Works

This works with PNG files, but not GIFs, because PNG saves partial-transparencies. Those partial transparencies will be blended at run time with whatever color is behind it. So, in our case, the light effects blend at run time with the background color we specify. Contrast with GIFs, which saves transparent or not transparent, but no in-between. So, you have to know ahead of time the color of the background. If you later change background colors, you have to re-save the image with the proper blending around the edges or it will have noticeable distortions around the transparent parts.

Small Caveat

PNGs do not render transparency correctly by default in IE 6 and below. However, there's a fairly easy fix for this. If you follow that site's directions for inserting the script it will only run on browsers that need it. It won't even get loaded on the others! The script essentially invokes a Microsoft proprietary transform (filter:progid:DXImageTransform.Microsoft.AlphaImageLoader, for the twisted among you that has to know) which correctly renders the image.

There are other scripts out there that accomplish this same thing, but this is the first one I ran across, and it has worked like a charm for me.

What's Next

One day, I'd like to see a cross between a programming API and an image format where I can store all my variations of a graphic in one file and change attributes of it at run time (like background color, or size) as needed for the task at hand through client-side code or CSS. It will require some intelligent design and layering on the part of the graphic artist, but it's reuse value will be extremely high.