Night of the Image Map

In the old days, before we thought much about web standards or the importance of accessibility, web designers used image maps to quickly divide a single image into regions, and link those regions to separate URLs. Traditional image maps, though, don’t work well with text-only browsers, and they aren’t as efficient or versatile as many newer techniques. You might still find them in use on an old web page or perhaps some kind of complex map, but most web designers would consider it an old technique. A dead one.

Article Continues Below

While collaborating on a horror fiction web project, I decided early on that I’d do my best to code the site using only standards-based XHTML and CSS. When the other designer sent me his concept for the site, I began to despair. He wanted the page to look like an old weathered book, with rough edges and grungy textures. The menu items were scattered about the page. How could I turn a well-structured document into something that looked so organic?

I thought about image maps.

They were horribly outdated, but an image map would make things so much easier than chopping the background image into dozens of pieces and trying to use CSS to stitch it back together. It might have been crazy to think about using them again, but the the old ways seemed to hold the answer. I decided to go back into the laboratory and see if I could use the modern science of CSS to bring this web design technique back to life…

These are the facts as we know them#section2

To make our image map, we’ll use CSS to create invisible links and float them over the background image wherever we need them to be.

First we create an outer div which will be used to apply the background image. Our links will go inside a nested div to keep our code organized and allow us to apply styles to the links as a group. The nested div can also come in handy when using a style sheet switcher to create alternate CSS menu effects.

<div id="book">
 <div id="menu">
  ...
 </div>
</div>

The individual links can now be placed inside our nested div. Giving each link its own id allows us to independently position them on the page. These separate ids also act as anchors, letting users select the links directly no matter where they are located on the page, or their ability to click on them.

To make the text within each link invisible, we need to add another nested tag. I prefer to use semantically meaningless <i> tags because they provide visual clues to their presence in the absence of a stylesheet, which makes them easier to work with. They’re also very short, which helps with code efficiency. However, you could certainly use <span>, <em>, or some other tag if you’d like. {Line wraps are marked ».  –Ed.}

<div id="book"> 
 <div id="menu"> 
  <a href="index.html" id="home"><i>Home</i></a>
  <a href="preface.html" id="preface"><i>Preface</i></a>
  <a href="stories.html" id="stories"><i>Stories</i></a>
  <a href="galleries.html" id="gallery"><i>Galleries<span 
 class="linewrap">»</span>
  </i></a>
  <a href="forums.html" id="forum"><i>Forum</i></a>
  <a href="mementos.html" id="mementos"><i>Mementos<span 
 class="linewrap">»</span>
  </i></a>
  <a href="credits.html" id="credits"><i>Credits</i></a>
  <a href="indicia.html" id="indicia"><i>Indicia</i></a>
 </div>
</div>

This is the all the XHTML that we need. You can see the results in Example 1. We can now move on to creating the image map effect with our stylesheet.

Guided by a master plan#section3

In your CSS file add a background color for the document body and set the margin and padding to 0. We’re going to be using absolute positioning, and this will help with our calculations. 

body {
  background-color: #000;
  margin: 0;
  padding: 0;
  }

The background for our image map is applied to the outer div. You should set an appropriate height and width to make sure it is fully displayed.

#book { 
  background-image: url(/d/imagemap/images/<span 
 class="linewrap">»</span>
   bookpages.jpg);
  height: 595px;
  width: 750px;
  }

Any styles that apply to the majority of the links can be defined together. More specific CSS rules can then be used to alter the attributes of individual links as required. Use absolute positioning and include a default height, width, and top position for all of the links. This is a good time to make sure the underlines are removed as well.

#menu a {
  position: absolute;
  height: 38px;
  width: 88px;
  top: 31px; 
  text-decoration: none;
  }

To hide the text within links while retaining “clickability,” we use a CSS selector to identify the italicized text within the links contained in our nested div, and its visibility is set to hidden. It’s important to include meaningful link text, even if it will be invisible to the majority of your users. This ensures that your site will be accessible for browsers that don’t support CSS and users who are viewing it with an alternate stylesheet.

#menu a i { visibility: hidden; }

Once the general CSS is in place, we can position each link individually. To improve efficiency, links that share a common attribute such as left or top, can be defined together.

a#credits, a#indicia { top: 531px; }
a#home { left: 101px; }
a#preface { left: 221px; }
a#stories { left: 311px; }
a#gallery { left: 431px; }
a#forum { left: 526px; width: 61px; }
a#mementos { left: 591px; width: 98px; }
a#credits { left: 431px; }
a#indicia { left: 591px; }

When applied to the XHTML of our document, the menu links will now float independently above our background image. If we position them above areas of the image that look like links, we’ll be all set. Placing your links correctly will usually take either careful calculation or a bit of trial and error.

CSS image maps can use the :hover pseudo element to define a separate style for each link’s rollover state. This allows us to float new images above the background whenever the user moves their mouse over one of the invisible link areas.

a#home:hover { background-image: url(/d/imagemap/<span 
 class="linewrap">»</span>
   images/homeglow.jpg); }
a#preface:hover { background-image: url(/d/imagemap/<span 
 class="linewrap">»</span>
   images/prefaceglow.jpg); }
a#stories:hover { background-image: url(/d/imagemap/<span 
 class="linewrap">»</span>
   images/storiesglow.jpg); }
a#gallery:hover { background-image: url(/d/imagemap/<span 
 class="linewrap">»</span>
   images/galleryglow.jpg); }
a#forum:hover { background-image: url(/d/imagemap/<span 
 class="linewrap">»</span>
   images/forumglow.jpg); }
a#mementos:hover { background-image: url(/d/imagemap/<span 
 class="linewrap">»</span>
   images/mementosglow.jpg); }
a#credits:hover { background-image: url(/d/imagemap/<span 
 class="linewrap">»</span>
   images/creditsglow.jpg); }
a#indicia:hover { background-image: url(/d/imagemap/<span 
 class="linewrap">»</span>
   images/indiciaglow.jpg); }

A bug in Internet Explorer that causes the rollover images to refrain from disappearing as expected can be fixed by adding border: none to the :hover state of all the CSS image map links.

a#home:hover,
a#preface:hover, 
a#stories:hover, 
a#gallery:hover, 
a#forum:hover,   
a#mementos:hover, 
a#credits:hover, 
a#indicia:hover { border: none; } 

You can see the final results of our CSS image map in Example 2.

Post mortem#section4

Using large background images isn’t bandwidth-friendly, but it can produce compelling designs and give high-bandwidth visitors a richer
visual experience. Because CSS image maps use standards-based XHTML, we could use a style sheet switcher to offer a low-bandwidth, alternate view of the site.

Special thanks to Nate Piekos and Shane Clark for their work on Dead Ends, Massachusetts, where the image map and other dark things were brought back from the grave.

67 Reader Comments

  1. “We have now taken up the policy that Netscape 4 users no longer have to be supported. In this debate I’m trying to convince everyone that it would be better “gracefully degrade” for Netscape 4 users.”

    Agreed. However, I would say that you still ARE supporting NS 4. As long as all the relevant (or important or mission-critical, or whatever) content and functonality is accessible and usable in NS 4, it is supported. It’s just the presentation that differs.

    My point is that one should be careful with the phrase “no need to support NS 4”, because it could be misinterpreted and (especially when it comes from us “standards” people) used as justification for making web sites that are completely unusable in NS 4.

  2. That’s all very good, but to be honest, CSS-P not image maps. OK maybe calling it image maps is useful for people that want to carry on in the old ways using the new technologies, whatever.

    Now, I was thinking the same as Lim Chee Aun on the

      thing.
      And using the CSS preloading hover is a good idea too.
  3. I wound up looking at this article hoping for a solution to a problem I have. I am trying to display charts that allow for heavy user interaction. The chart package I use happily provides an easy way to generate an image map. BUT — the effect I want is for the user to see the each chart region highlighted as the mouse hovers over it. Imagine the user is presented with a pie chart and when she hovers over a pie slice the border of slice becomes red instead of black. When the user clicks on the pie slice they get a menu that allows them to manipulate the chart in useful ways (for example change the color of the pie slice or see detail information)

    This sounds like it ought to be a simple straightforward task for an image map, but is not. I have tried code such as this:
    —————————code begins————————-


    1

    2



    ——————————code ends————————-
    But without success — it does not reliably work.
    I think that perhaps the only way I will be able to get the effect I want is to build — on the fly — transparent GIFs that show my desired outlines and use a rollover to display them. This is a pretty heavy weight solution both in terms of server resources and also from a number of images downloaded perspective — but seems to be the only way I am gonna get this effect in a reliable manner.
    Any better ideas out there??? Thanks for reading.

  4. Charles it sounds as if you need a technology like flash or more likely SVG. Transform your charts into an interactive SVG image which can be scripted to provide the functionality that you want. People would then just need adobe’s svg viewer plugin.

    I think there are ways to do it with CSS and HTML but SVG is a more appropriate technology.

  5. I like it too, and it does appear to meet accessibility for those who use screen readers. However, it does not appear to meet accessibility for people with low vision who do not use screen readers. I tried changing the font size in Mozilla using View/Text zoom and it (as expected) has no effect.

    So somebody would have to code additional styles in their personal style sheet to navigate this page. (I don’t see any quick setting in Mozilla to ignore the currently active style sheet.)

  6. This method strikes me as a good way to create html-only versions of graphic-intensive flash sites. I agree, I’d rather use spans and have my markup a little less clear than use a deprecated tag like – call me a purist but it just seems wrong! Maybe use instead? Cool idea overall though.

  7. The idea of css was originally that it was less of a hack than html – more elegant, more maintainable. But now we are seeing so many ‘techniques’ in css which are much more complex that the html methods they replace… such as this one. I don’t approve. css pages still don’t render the same in different browsers anymore than html code did. css has not proven to be an advantage, and this article is one more example of that.

  8. The approach worked better then a map in our application and also reduced the final size of the code. Thank you for taking time to share your solution !! Some of us appreciate your efforts.

  9. This solution, with the enhancements on the li and preload-stuff, seems very logical and flexible to me. For those who aren’t convinced: Imagine how you can print this page. Just make a print-stylesheet and there you go!

  10. In my summer job I ran accross a similar problem and reached a slightly different solution. Keep in mind though that I was designing only for IE6 (not a project that went to the web) so I was free of many constraints and constrained in many other ways.

    I kept the background image just one whole image with the actual lettering (non glowing). I made an invisible link over the lettering (absolutely positioned) that contained a hidden (visibility: hidden;) image (the glowing lettering) that was shown by calling a javascript function when the mouse over rolled over (onmouseover) and hid it when it was rolled out (onmouseout).

    Of course this doesn’t rely purely on XHTML and CSS and I didn’t really look into accessiblity and other such issues, but it was definely a lot less code than this technique and seems sound. I am sure with just a little more code this can be made accessible as well.

  11. Nice article. Unfortunalley it will only work in IE 5 and 6, if image is located in the upper-left corner.

    If you set the body.margin to 50px, then it does not work. Althoug the CSS Map should be relative to the parent div object.

  12. I really liked this article as it solved a problem for me with Elastic Design (see the “Elastic Design” article else where on this site). I was trying to create an elastic design where the images would scale in proportion to the rest of the text on the page. The problem was the specs required that certain images be clickable via image maps. How do you get an image map to scale when all of the coords are specified in pixels? Answer, you can’t. This method does however!

    I’m including my sample code below so I can point out one minor problem I found in IE6. For the longest time, I couldn’t seem to click on the area I had defined except when I was directly over the small border I had made around the link (so I could see it). If I removed the border, I couldn’t click on the link at all! The answer seemed to lie with the background of the link. As soon as I set one, I could click on the area. We use a single transparent GIF in our pages for tracking and other purposes, which made me decide to try using it as a transparent background for the link. This solved the problem. Here’s the code in case any one else wants to review it.



    Untitled


  13. In “Separate CSS file”…, Gabe wrote:

    If you use Safari, try the Activity window. It gives a list of all open URLs and components of those pages so you can get to the stylesheet (and anything else) quickly.

    This is fantastic! I can’t believe I didn’t already know this. I’ll use this daily.

    Thanks for the valuable hint Gabe.

  14. I think, that in example very hard pictures 🙁
    In the net with slow modem this page will download very very long time…

Got something to say?

We have turned off comments, but you can see what folks had to say before we did so.

More from ALA

I am a creative.

A List Apart founder and web design OG Zeldman ponders the moments of inspiration, the hours of plodding, and the ultimate mystery at the heart of a creative career.
Career