Skip to Navigation

NavSwap: Semantic XHTML Menus into Designer Images

The Problem:
If you are a web designer who tries to combine high standard graphic design with top-notch web-standards xhtml, you can’t escape a certain degree of conflict of interests. This can be especially acute when it comes to designing a menu. You want it to have a strong graphic look, elegant and glossy, and yet you’d rather use a semantic xhtml list with text links.

Your life might get somewhat easier when it comes to headings, with various CSS Image Replacement techniques. But they’re not perfect either, and for menus you need be able to hyperlink the image.

Available Solutions

    So what can you do?

  1. Use CSS to format your textual menu to it’s best abilities, using the same old fonts and maybe a background image to make it look nicer. Don’t even think about using an interesting font like Arcitectura, or adding some layer effects in PhotoShop, because then you’ll have to use images.
  2. Employ images, which is not very semantic and requires you to add lots of additional markup, such as img and alt tags, and then you’ll need to add JavaScript calls for rollovers, and change the image of the current menu item on each page. What’s next? Design with tables…?
  3. Design a Flash navigation bar, which is again not very semantic, SO friendly, or accessible. I’ve nothing against Flash, in fact, I I’m a huge fan. It can be used to great effect to add an extra dimension to the website with animation and interactivity. But just like salt and pepper, you need to know when to stop adding it. Graphics or drop down menus are not a good enough reason for a Flash menu – these can always be accomplished by dhtml. A Flash navigation needs to be exceptional (or at least quite interesting) to justify itself, and even then you’ll need to add textual navigation somewhere on the page, at least for the search engines.

Most of my xhtml websites up to date have been achieved with the first method. Take a look at my own website, for example – it uses CSS and background images for formatting, and the font defaults to a generic serif. Even then, it took a lot of work and a bit of extra markup to achieve the look.

NavSwap:
My latest website project (not yet published as this goes to “print”, but soon to come) is for a glossy fashion wholesaler, and that meant top-notch graphics, even for the menu. For this I came up with option #4 – NavSwap, which happens to be the object of this article. It took some code wrangling to write, but is quite easy to implement.
You can download the script and examples here…

NavSwap serves two functions:

  1. Swaps semantic xhtml into images, using unobtrusive JavaScript. That is, if JavaScript is unsupported, you get an xhtml text menu, otherwise you get images, complete with alt tags generated on the fly.
  2. Automatically swaps images on rollovers and swaps the current menu item with an active state item on each page.


The html markup:

<ul class="nav" id="nav">
<li><a href="index.htm">Home</a></li>
<li><a href="about.htm">About</a></li>
<li><a href="awards.htm">Awards</a></li>
<li><a href="emporium.htm">Emporium</a></li>
<li><a href="suppliers.htm">Suppliers</a></li>
<li><a href="contact.htm">Contact</a></li>
</ul>

This is mostly all the html you will require. The script will cycle through the menu items and use each item’s text value for the name of the image that will be replaced (converted to lowercase, with extension and directory path added), and also uses it to generate the alt text.
If, however, your menu item’s text requires spaces, characters or markup unsuitable for file names, or is duplicated across menus (with different images), or for any other reason, you can assign a className to the item’s to override it. For example:

<li><a href="joinus.htm" class="joinus" >Join Us </a></li>

You can also add an idto the body tag. The id’s value should correspond to the text of the menu item, or the overriding className. This will mark the page as active, and the script will automatically change the image of the corresponding item to the active state:

<body id="home">

Organising The Images:
Next, you’ll need to prepare the images using PhotoShop or your favourite image editing software. You will need to create images for two or three different states, using the same file names (home.jpg, about.jpg etc.) but organised in different directories:

  1. Up: The images as they appear in their normal, or “up” state.
    Default directory: “images/nav_up/“.
  2. Over: The rollover images.
    Default directory: “images/nav_over/“.
  3. Active: The active images for each page. By default, the script uses the Over images for the Active state. But it is possible to create separate images for this purpose, by switching a variable in the script.
    Default directory: “images/nav_over/” – but can be changed, for example, to: “images/nav_active/”.

These paths are user-customisable by passing the through the following variables in the navSwap.js file:

var navUpPath = "images/nav_up/";
var navOverPath = "images/nav_over/";
var navActivePath = "images/nav_over/";

– Or by passing the new directory paths to the navSwap() method (see below).

The names of the images should be the same throughout the directories, and consistent with the text of the menu items. For example:

<li><a href="index.htm">Home</a></li>
--> home.jpg
<li><a href="about.htm">About</a></li>
--> about.jpg

The JavaScript:
The text menu will be swapped for the images using JavaScript. To do this, you need to add the link to the external script to the head of the page:

<script type="text/javascript"
src="scripts/navSwap.js"></script>

And place a call to the method right after the menu:

<script type="text/javascript">
navSwap("nav", 90, 30, "jpg", "images/nav_up/", "images/nav_over/");
</script>

For each menu or submenu in your document you need to use a separate call to the navSwap method, passing the following optional parameters: (id, w, h, suffix, upPath, overPath, activePath):

  1. id: The id of the menu <ul> that is to be replaced. If this parameter is not passed it defaults to “nav”. However, it can be particularly useful if you have multiple menus or submenus. Each of these will need its own id.
  2. w: Width of the images that replace the menu. The images should all be the same width if this parameter is used.
  3. h: Height of the images that replace the menu. The images should all be the same height if this parameter is used.
  4. suffix: The default is “.jpg”, but could be changed to “.gif” or “.png”.
  5. upPath: The up state images path.
  6. overPath: The over state images path.
  7. activePath: The active state images path.

The script works with multiple menus, as long as each has it’s own id, so you could combine this method with drop-down menus and other techniques.

Design Issues
Of course, menus don’t always come in the shape of a list, so you will need some CSS formatting to finish off the look. You can use CSS to position the menu, add margins or padding, and maybe change it from vertical to horizontal ( .nav li {display:inline}).

Also, since we’re adding the JavaScript unobtrusively, you could add a bit of extra styling to the menu with CSS, to make it look as good as it can when JavaScript is disabled.

Unfortunately, I couldn’t find a way to detect if images are disabled in the browser. If anyone knows how to do that, please let me know. If, however, images are disabled, this technique at least ensures that you see their alt tag replacements instead. This looks better in Firefox than in IE, but at least it’s still useable.

Download:

The navSwap script, example and all supporting files can be downloaded here

If you want to have a look under the hood, the script is commented throughout.

I hope you find it useful.

Update, May 2012

Since I wrote this blog post in 2006, better ways have emerged to handle image replacement with CSS.  Also, with the advances in font embedding, image replacement is no longer recommended if you simply want to use a fancy font.

14 responses to “NavSwap: Semantic XHTML Menus into Designer Images

  1. That’s a shame – my mac is so old I can’t even install Safari on it, so currently it’s used for sticking notes on. Can you tell me what happens to the page on Safari? Also, have a look at htttp://www.fashiondevelopments.ie – does the navSwap code on that page work on Safari?

  2. WOW. Thanks for the quick reply.

    On the site I am building the links are there but the img are not showing up. (the cursor changes to a hand to click but there is no image.) If you right click to click to open image in new window, it shows it. http://www.2ndmileproductions.com/glen

    The link you gave me does not work either. The cursor does not even change to a hand to show that there is a link present.

  3. Got it!

    It is this line in the JS file.

    if (supported && hidden){
    document.write (” .nav{visibility:hidden;} “);
    }

    Take that out and it shows fine in Safari.

  4. Hmm… It sounds as it disabling a style sheet is not supported in Safari.
    if you could put the line back, and place these alerts at the very end of the navSwap function:
    alert (hideNav)
    alert (typeof (hideNav))
    alert(hideNav.disabled)

    Could you tell me what they show up as?

    Also, after you’ve done this and got rid of the alerts again, could you exchange the document.write function with the following:

    var safari = navigator.vendor && (navigator.vendor.indexOf(“Apple”) != -1)
    alert (safari)

    //Hide the menu, to avoid an ugly jump if the page loads slowly
    if (supported && hidden && !safari){
    document.write (“

    “);
    }

    Thanks,
    Karina

  5. Here’s another test to try out, which should (if works) get the best results.
    Start with the _original_ navSwap code (minus browser testing and removing the styles).
    Then place this bit of code towards the end of the function:
    nav.style.visibility = “visible”;

    Let me know how you get on, and I’ll update the code.

  6. “Hmm… It sounds as it disabling a style sheet is not supported in Safari.
    if you could put the line back, and place these alerts at the very end of the navSwap function:
    alert (hideNav)
    alert (typeof (hideNav))
    alert(hideNav.disabled)

    Could you tell me what they show up as?”

    [object Style]
    object
    true
    With no menu, but the cursor still changes as if the links are there. The images are just not present.

    _____________________

    “Also, after you’ve done this and got rid of the alerts again, could you exchange the document.write function with the following:

    var safari = navigator.vendor && (navigator.vendor.indexOf(”Apple”) != -1)
    alert (safari)

    //Hide the menu, to avoid an ugly jump if the page loads slowly
    if (supported && hidden && !safari){
    document.write (”“);
    }”

    Shows formatted ul WITHOUT the substitutions happening.

    ______________________________

    Then place this bit of code towards the end of the function:
    nav.style.visibility = “visible”;

    Shows formatted ul WITHOUT the substitutions happening.

  7. Could you try this instead?

    if (supported && hidden){
    	if (document.createStyleSheet){
    		document.createStyleSheet().addRule(".nav", "visibility:hidden");
    	}else if (document.getElementsByTagName){
    		var style = document.createElement("style");
    		style.type = "text/css";
    		style.innerHTML = ".nav{visibility:hidden;}"
    		document.getElementsByTagName("head")[0].appendChild(style);
                }
    }
    

    and then – nav.style.visibility = “visible”; at the end of the function.

    Thanks,
    Karina

Leave a Reply

Your email address will not be published. Required fields are marked *