Skip to main content

A semantically written menu that uses a single image and swaps accompanying text descriptions in an accessible manner.

- (incept: )

Accessible & semantic image rollover menu

Last updated: 22nd June 2006

A semantically written menu that uses a single image and swaps accompanying text descriptions in an accessible manner.

First a demo, try it via keyboard too:

Update 22nd June 2006 placed cdata tags in example and conditional commented the old underscore hacks for IE.

A barebones version of the accessible & semantic image rollover menu [11KB] is available.

How it works

menu background image

A single image is used to achieve the effect. The normal state above the hover / focus state.

The list element, in this case an ordered list, is defined to display only the top half of the image as a background.

The area of each link is set using absolute positioning. Not exactly the easiest thing to do but packages such as Fireworks from Adobe help.

The hover / focus state uses small sections of the same image as a background.

The text, held in span, is also positioned absolutely with its visibility set to hidden, that is until the link is hovered or focused.

The coding specifics

Minimal (X)HTML is required but a lot of CSS.

The (X)HTML:

<ol id="menu">
  <li id="description">Menu - default description (optional).</li>
  <li><a id="item1" href="#" title="Step 1 - Specify your needs"><span>Step 1 - Specify your needs</span></a></li>
  <li><a id="item2" href="#" title="Step 2 - Do your research"><span>Step 2 - Do your research</span></a></li>
  <li><a id="item3" href="#" title="Step 3 - Follow a route"><span>Step 3 - Follow a route</span></a></li>
  <li><a id="item4" href="#" title="Step 4 - Brief your suppliers"><span>Step 4 - Brief your suppliers</span></a></li>
  <li><a id="item5" href="#" title="Step 5 - Evaluate the responses"><span>Step 5 - Evaluate the responses</span></a></li>
  <li><a id="item6" href="#" title="Step 6 - Award the contract"><span>Step 6 - Award the contract</span></a></li>
  <li><a id="item7" href="#" title="Step 7 - Manage the contract"><span>Step 7 - Manage the contract</span></a></li>
  <li><a id="item8" href="#" title="Step 8 - Close the loop"><span>Step 8 - Close the loop</span></a></li>
</ol> <!-- id="menu" -->

An id is assigned to the list (menu), the default description li (description), and the link to each step (item1-8).

The text in each link is embedded in a span element and replicated in the link title

An ordered list was chosen because of the linear steps implied by this menu. I don't envisage any difficulties using unordered lists though definition lists may be problematic.

The styling:

  1. Setup the menu main block (<ol id="menu">):
    #menu {
      position:relative; width:390px; height:160px;
      background:url(menu.png) #fff 0 0 no-repeat;
      padding:0; margin:0 auto
    • position relative and width is stated to prevent Mac IE 5 issues
    • height is stated to limit the display area
    • background image is placed top left with no-repeat
    • padding and margins are removed and the block centred.
  2. Remove global and browser styling from all the sibling elements:
    #menu * {
      margin:0; padding:0; border:0 solid;
      text-decoration:none; list-style:none
  3. Set-up general properties for each sibling element used:
    #menu a     {position:absolute; display:block; width:34px; height:34px}
    #menu span  {position:absolute; visibility:hidden; width:230px; min-height:150px; background:#fff}
    /* And in rollover_ie.css just for IE */
    #menu li    {width:230px; height:0}
    #menu span  {height:150px}
    • outlined li block areas in IElist items have width and height set for IE browsers
    • links are set for positioning and state the active area size
    • spans contain the descriptive text and are hidden from view but not screen readers. Height and background colour overwrite the default text.
  4. Set the optional default description:
    #description {
      top:5px; left:163px; width:230px

    Top and left positioning are relative to the ordered list block, that is the whole white area in the demo.

  5. outlined link areas Position each link area:
    #item1 {top:0; left:63px}

    Position is relative to the top left of the ordered list block (white area in the demo).

  6. Position the background to each link rollover:
      {background:url(menu.png) -64px -160px}

    Position is relative to each link area this time. That is 0,0 is the top left of the link.

    The background image needs to be repositioned so the link area, when hovered on, displays the correct part.

    Basically move it left (-64px) and up (-160px).

  7. Position each span containing the link text:
    #item1 span {top:5px; left:100px}

    Again position is relative to the link area.

  8. Repeat positioning (5 to 7) for #item2 to #item8. that's the quickest to say but the longest to do. I suggest using a graphics package such as Fireworks to make this easier.
  9. Finally, on focus or hover, make the link text in the span visible:
    #menu a:hover span,
    #menu a:active span,
    #menu a:focus span {visibility:visible}


IE v5 does not understand "a:hover span {...}", bless. The menu functions correctly but it loses the effects, still accessible but not as pretty.

So I thought I'd be kind and add the effects via JavaScript within a conditional comment.

<!--[if IE 5]>
  <script src="ie5_rollover.js"></script>

Only IE v5 gets to see the JavaScript. You can find out more about conditional comments in "Useful CSS snippets"

The usual add event function (credit function to?):

function addEvent(func) {
  if (!document.getElementById | !document.getElementsByTagName) return
  var oldonload=window.onload
  if (typeof window.onload != 'function') { window.onload=func }
  else {
    window.onload=function() { oldonload(); func() }

A quick and dirty hide all span text:

function hideall (){
  for (var i=0;i<8;i++){

Attach mouse and focus events to the link objects:

function attachBehaviourTo(id){
  var obj0 = document.getElementById(id)
  obj0.onmouseover= function() {
  obj0.onfocus=     function() {
  obj0.onmouseout=  function() { hideall() }
  obj0.onblur=      function() { hideall() }

The list of objects (links) to add behaviours to:

function init() {
  for (var i=1;i<9;i++){


The example works in IE v5.0, 5.5, 6 and Firefox v1.5 on a PC and Opera v8, Firefox v1.5, Safari v2 on a Mac.

With IE v5.2 on a Mac the rollovers work but the span text doesn't. This is due to the browser not understanding the conditional comments that supplies the JavaScript to IE v5. A workaround could be made but seemed worthless as the basics of the system are still functional.

For your convenience a small zip file containing the demo plus minimum mark-up is available: accessible & semantic image rollover menu [11KB]

Good luck.