I'm Dudley Storey, the author of Pro CSS3 Animation. This is my blog, where I talk about web design and development with HTML, CSS and SVG. To receive more information, including news, updates, and tips, you should follow me on Twitter or add me on Google+.

my books

Pro CSS3 Animation, Apress, 2013

Using SVG with CSS3 and HTML5, O'Reilly, 2017

my other blogs

Massive Head Canon: Intelligent discussion of movies, books, games, and technology.

my projects

The New Defaults — A Sass color keyword system for designers. Replaces CSS defaults with improved hues and more memorable, relevant color names.

CSSslidy — an auto-generated #RWD image slider. 3.8K of JS, no JQuery.

Enhancing Imagemaps With CSS3 Popups

Advancing imagemaps into the 21st century

The venerable imagemap has been with web developers since 1993. One of the first popular ways of creating a website graphical user interface, imagemaps were quickly embraced, pushed way too far, and then neglected as developers moved on to shinier tools such as Flash and JavaScript. However, the <map> tag is still supported in HTML5… and as I’ll demonstrate here, adding CSS reinvigorates the element, making it a real contender against other techniques.

The concept of an imagemap is simple: create a series of “hotspots” on an image that become clickable hyperlinks for the user. Traditionally, these were links to other pages in a site; here, we’ll keep the user engaged with the imagemap by making it more interactive and informative with CSS popups.

An appropriate image for an imagemap can be anything that consists of visually discrete components: maps are an obvious possibility, as are almost anything mechanical. In the example here I’m using my beloved Lynskey Backroad touring bike.

Understanding Imagemap Syntax

Once you’ve decided on your image, we need to create the basic imagemap code. I would strongly recommend that you use a graphical editor to do so: plotting the coordinates for image hotspot areas by hand is not fun. (I’ve covered how to make an imagemap with DreamWeaver in this blog; the imagemap plugin in GIMP is another possible tool).

However you choose to create the code, it’s worthwhile understanding the syntax, as we’ll be amending it shortly. Here’s the code for the image above, with the attached imagemap simplified to include just the bike’s frame and saddle:

<img src="2011-lynskey-backroad.jpg" alt="Lynskey Backroad Bicycle" style="width:100%;height:auto" usemap="#bikemap">
<map id="bikemap">
<area shape="poly" coords="265, 117 ,331, 328, 360, 325, 383, 340, 519, 173, 535, 166, 514, 97" href="#" alt="Titanium frame">
<area shape="rect" coords="195, 36, 324, 75" href=# alt="Selle Italia X1 Flow Saddle">
</map>
Imagemap with areas highlighted

As you can see, the image has the standard alt attribute, together with an inline style that sets its width and height. The unique part of the image is the usemap property, which references the id of the map element immediately underneath it. (The map code could be anywhere on the page, but it usually makes sense to place it under the referring image).

map contains several area elements. These shapes may be circles, rectangles or multi-point polygons, depending on the appearance of the image underneath: for example in the case of the saddle, it makes sense to make the area a simple rect shape. The bicycle frame (highlighted in the image to the right) is a polygon. The coordinates for every imagemap shape are relative to the image itself.

Finally, each area has an alt property that describes what is underneath it, allowing the imagemap to be accessible to disabled visitors.

Adding Information Popups

That’s your basic imagemap. What we want to do now is enhance the code with visual popups containing more information: either on mouseover, or when the user clicks on a feature in the image.

First, we’re going to wrap the code in a <div>, to provide an easier frame of reference:

<div id="bikenav">
<img src="2011-lynskey-backroad.jpg" alt="Lynskey Backroad Bicycle" style="width:100%;height:auto" usemap="#bikemap">
<map id="bikemap">
<area shape="poly" coords="265, 117, 331, 328, 360, 325, 383, 340, 519, 173, 535, 166, 514, 97" href="#" alt="Titanium frame">
<area shape="rect" coords="195, 36, 324, 75" href=# alt="Selle Italia X1 Flow Saddle">
</map>
</div>

You’ll note that when you click on the image hotspots they have a blue outline, even if the page doesn’t go anywhere. We’ll turn off that annoying feature in our CSS:

area { outline: 0; }

Next, we’re going to add container elements after each area . These new elements – div containers, in our case – will contain our popup text.

<area shape="rect" coords="195, 36, 324, 75" alt="Selle Italia X1 Flow Saddle" href="#saddle">
<div id="saddle">Selle Italia X1 Flow Saddle</div>

The map element is surprisingly flexible in what it will contain. The elements we add could be almost anything: <figure>, <p> or <iframe> tags, among others. In turn, those elements could also contain almost anything: text, images, even other interactive content.

Note that the href attribute of the area tags now reference the unique id values of the added div elements. Right now, that means that clicking on the area on the imagemap will “jump” the page to the location of the associated div , which is visible somewhere below the image. We want to change that: the divs should located be on top of the image, invisible at the start, and only visible on click. Almost all of this happens in our stylesheet. The code becomes:

body { font-family: Futura, Arial, sans-serif; }
area { outline: 0; }
div#bikenav { position: relative; }
div#bikenav div { width: 300px; padding: 12px; position: absolute;  background: rgba(238,238,238,0.78); border: 1px solid rgba(177,177,177,0.8); border-radius: 2px; font-weight: bolder; opacity: 0; }

We’ll position each div at the right location by manipulating its top and left values; you’ll want to temporarily turn on opacity , and perhaps use a graphical editor to see where the divs are being moved to:

div#saddle { top: 35px; left: 330px; }
div#frame { top: 50px; left: 200px; text-align: center; }

To make the appropriate div appear on click, we’ll use :target

div#bikenav div:target { opacity: 1; }

The browser no longer “jumps” to the location of the new divs on click, as they are now absolutely positioned, but we want the information boxes to truly “pop” into existence. To do that, we’ll transition both the opacity and the scale of the elements, using a cubic-beizer curve forced in extermis to create a push-pull animation:

Adding CSS Transitions

div#bikenav div {
opacity: 0; transform: scale(0.8); transition: .4s all cubic-bezier(.06,.62,.73,1.5);
}

And for the pop-up divs:

div#bikenav div:target { opacity: 1; transform: scale(1); }

One Important Caveat

There is just one drawback to this technique: by default, the browser will automatically jump to the vertical position of the target, if the page is longer than the browser window. This behaviour is built into the browser: it is possible to turn it off with some JavaScript, but if we do so current browsers will also disable any CSS we’ve applied to the imagemap. This is an acknowledged bug. Right now, a make-do solution is to drive the browser back up to the top of the page with a little JavaScript:

var areas = document.querySelectorAll("map area");
for(var x=0; x<areas.length; x++) {
areas[x].addEventListener("click", function(e) {
setTimeout(function() { $(window).scrollTop(0) }, 1);
});
}

This is not a perfect solution, but it’s enough to stop the browser jumping around.

This site helps millions of visitors while remaining ad-free. For less than the price of a cup of coffee, you can help pay for bandwidth and server costs while encouraging further articles.