There are many ways to create image galleries: JavaScript, , Flash and more. But all that is required, in most cases, is some simple combined with semantic markup.

To complete this exercise, you’ll need three thumbnail photographic images, ideally all the same size, and three matching large versions of those same images. For clarity, save the large versions of the images as subject.jpg and the small versions as subject_thumb.jpg.

Once you have your content, the question is what markup makes the most semantic sense to wrap around it. What we desire is a set of interactive thumbnail images that reveal larger versions of themselves, including an explanation of the picture's context and meaning. Here, the incredibly useful (and unappreciated) definition list comes to our aid: we are, at heart, talking about a series of terms (which could be words, images, links, or anything else) that are expanded upon with a definition.

The basic markup is fairly straightforward:

<dl id="simple-gallery">
	<dt tabindex="1">
		<img src="london-thumb.jpg" alt>
	<dd>
		<img src="london.jpg" alt>
	<dt tabindex="2">
		<img src="paris-thumb.jpg" alt>
	<dd>
		<img src="paris.jpg" alt>
	<dt tabindex="3">
		<img src="san-francisco-thumb.jpg" alt>
	<dd>
		<img src="san-francisco.jpg" alt>
</dl>

(Note that for the purpose of this exercise I am assuming that every thumbnail is the same size, so I could put their width and height as part of a declaration:

dl#simple-gallery dt img { }

If the thumbnails were all different sizes, you would put the width and height as separate inline styles for each image, as you normally would for the large images. I have left the alt values for the images blank with markup shortcuts for the sake of clarity.

On viewing the web page in our browser we’re immediately confronted with several problems. The first is that our large images are visible, and we only want them to appear when the user hovers over a thumbnail image.

There are many CSS properties that can be used to make elements on a web page “disappear”: display, visibility, pushing things off the screen with margin or left, and more. We will use opacity:

dl#simple-gallery dd {
	opacity: 0;
}

That hides our large images, but preserves the space they take on-screen. We’ll get around this by positioning the <dd> elements absolutely:

dl#simple-gallery dd {
	opacity: 0;
	position: absolute;
}

Using absolute positioning on elements takes them out of the “flow” of the document: the web page acts like the definition declarations are no longer there, and collapses the remaining structure of our document. (The <dd> elements and the images they contain are still present, of course, simply hidden by our opacity: 0 rule. You could see where the images are by removing or commenting out that part of the style declaration.)

position: absolute is very useful, but very dangerous – if not used carefully, it leads to positioning every element on the page absolutely, due to designer’s misplaced desire for “pixel-perfect layout” and the aforementioned collapse due to the removal of absolutely positioned elements from the flow of the document. position: absolute should, as a general rule, be avoided unless it is absolutely required – and when used, you should know why you are using it, rather than “it just works this way”.

In this case, position: absolute is used for an eminently logical reason: we want all of our large images to appear in the same location. Right now, they are not (again, turn off opacity: 0 temporarily to see where they are). In addition, we want the position of the large images to be measured in respect to their relation to the definition list as a whole. This is a two-step process. First, some CSS for the definition list itself:

dl#simple-gallery {
	position: relative;
}

The reason for this line is a simple rule: absolutely positioned elements position themselves against the origin of the body (i.e. the top left corner of the web page), unless they are within another absolutely positioned or relatively positioned element.

In essence, we’ve told the absolutely positioned <dd> elements to measure their position against the definition list, rather than the body. We can see this by once more temporarily commenting out the visibility of the <dd> elements and adding more CSS to the style declaration:

dl#simple-gallery dd {
	/* opacity: 0; */
	position: absolute;
	top: 20px;
	left: 200px;
}

Naturally the numbers for left and top are guesses; you should feel free to adjust them to suit your particular design before turning visibility: hidden back on.

The penultimate step is to make the <dd> elements appear only when we are hovering over the thumbnail images. Looking at our markup, we can see that each <dd> element is immediately preceded by a <dt>. We also recall that :hover can be applied to any element, not. Ergo, the solution is a combination that employs an adjacent selector:

dl#simple-gallery dt:hover + dd, dl#simple-gallery dt:focus + dd { 
		opacity: 1;
}

The CSS interacts with our HTML markup to create the effect of the large images appearing when the mouse is moved over the thumbnail images, touched on a mobile device, or when the TAB key is pressed (due to the use of tabindex in the markup, as we also want our page to be accessible.

This solution is a good one, with just one remaining problem: you can make the large images visible by moving your mouse or touching to the right of the thumbnail images, where the <dt> is still active. This is due to the fact that <dt> is a block tag, and therefore stretches all the way across the page by default. But if it’s a block tag, we can apply width to it. Assuming that your thumbnail images are all 75 pixels wide:

dl#simple-gallery dt {
	width: 75px;
}

The complete CSS code:

dl#simple-gallery { 
	position: relative;
}
dl#simple-gallery dt {
	width: 75px;
}
dl#simple-gallery dd {
	opacity: 0;
	position: absolute;
	top: 20px;
	left: 200px;
}
dl#simple-gallery dt:hover + dd, dl#simple-gallery dt:focus + dd {
		opacity: 1;
}

Photographs by Trey Ratcliff, licensed under Creative Commons.

Enjoy this piece? I invite you to follow me at twitter.com/dudleystorey to learn more.
Check out the CodePen demo for this article at https://codepen.io/dudleystorey/pen/rBnHl