TJKDesign: Home Page

ez-css Putting the 'less' in table-less layouts. css-101 logo
Bookmark this article at these sites:

Using CSS to style thumbnails and captions.

The challenge:

  • captions must be centered underneath their image
  • captions may contain up to three lines of text
  • elements must flow (number of image/caption pairs in a row depends on the width of the parent container)
  • thumbnails may be of various widths
  • text resizing must not break the layout
  • markup must be semantic (no structural hack)
  • markup must be "hook free" (no ID, no CLASS)
  • CSS must be plain and simple (no filters, no Conditional Comments)
  • must be browser-friendly

Take a sneak peek and also make sure to check these other examples that use "zoom", "-mox-inline-stack", "table-cell", etc.:

Let's look at this step by step.

The markup

I think a DL (Definition List) is the most appropriate element to use here as we are dealing with a list of elements that are paired. I'll be using the DTs to hold the thumbnails and the DDs to hold the captions (you're free to argue this point).
Also, note that I have added A elements as in real life these thumbnails would be linked to larger images.

<dt><a href="#"><img src="img/00.jpg" alt="Teacups" /></a></dt>
<dd><em>Teacups</em>Pte de Vanves</dd>
<dt><a href="#"><img src="img/01.jpg" alt="Soldiers" /></a></dt>
<dd><em>Soldiers</em>Pte de Vanves</dd>
<dt><a href="#"><img src="img/02.jpg" alt="Paris facade" /></a></dt>
<dd><em>Paris facade</em></dd>
<dt><a href="#"><img src="img/03.jpg" alt="La Conciergerie" /></a></dt>
<dd><em>La Conciergerie</em></dd>
<dt><a href="#"><img src="img/04.jpg" alt="Pont Neuf" /></a></dt>
<dd><em>Pont Neuf</em> The oldest bridge in Paris</dd>
<dt><a href="#"><img src="img/05.jpg" alt="Jeanne d'Arc" /></a></dt>
<dd><em>Jeanne d'Arc</em> Near the Louvre</dd>
<dt><a href="#"><img src="img/06.jpg" alt="The Louvre" /></a></dt>
<dd><em>The Louvre</em></dd>
<dt><a href="#"><img src="img/07.jpg" alt="Place Vendôme" /></a></dt>
<dd><em>Place Vendôme</em></dd>
<dt><a href="#"><img src="img/08.jpg" alt="Sculpture" /></a></dt>
<dt><a href="#"><img src="img/09.jpg" alt="" />The Seine</a></dt>
<dd><em>The Seine</em> View from the left bank</dd>

This is how it appears in the browser without any style applied

The concept

It is beneficial to understand how things work before applying the necessary styles, so some background colors and a border will help illustrate the "basics".

  • Step 1: We apply background colors to DTs and DDs and we set a border around the DL, which helps us notice a few things:
    • DTs seem to be the same width as their parent container (the DL), but browsers apply a left margin to the DDs.
    • There is a gap below each image.
  • Step 2: We've fixed both issues by using "margin-left:0" in the DD {...} rule and "vertical-align:center" in the img {...} rule. Note that we could have used a different fix for the images (see Doctypes issues), but I chose that one because it is the most useful for what comes later (centering the elements).
  • Step 3: It's time to give a width to these DTs and DDs. Any value will do as long as we make these elements at least as large as the largest element they contain (it can be an image or a string of text that you do not want to wrap). For our example, 10.5em seems to be the perfect value as it creates some "room" that will keep these elements from getting to close to each other at small text-size value (the reason why I'm using EM rather than PX here).
  • Step 4: We remove the border around the images and add "float:left" to our DT,DD {...} rule so that these elements flow next to each other. Note that the border around the DL has now collapsed; this is because floats are removed from the elements flow.
  • Step 5: To make sure the DL wraps these floats we can apply one of these two declarations (I chose the latter as it is more browser-friendly):
    • overflow:hidden
    • float:left
  • Step 6: This is the secret weapon; setting proper margin values on the DDs does all the magic. I simply replace the "margin-left:0" declaration we had with "margin:75px 0 0 -10.5em". Note that the top margin equals the height of our images while the left margin has a negative value equal to the width of the element itself.
  • Step 7: Again, it is a margin value that lets us make sure thumbnails can "escape" (I don't want to use the term "clear" here) the ones with a two line caption, when displayed on multiple rows. So I add margin-bottom:2.5em to the DT {...} rule. 2.5em should be just enough to pass underneath the DDs containing a caption with two lines of text.
  • Step 8: We create a new rule, em {display:block;}, to display the text within the EM elements on its own line. Note that because of this new line it is necessary to increase the space below the DTs to make sure elements can freely flow to the left without being "caught" by a previous DD.
  • Step 9: The last thing to do, besides removing the background and border declarations, is to center images and text. To do so, I simply use "text-align:center" in the DL {...} rule.

The CSS rules

Short, plain and simple. I have highlighted the values that must match.

dl {float:left;text-align:center;}
dt,dd {width:10.5em;float:left;}
dt {margin-bottom:4em;}/* vertical space between the images */
dd {margin:75px 0 0 -10.5em;}
img {vertical-align:bottom;border:0;}

With a few more rules we end up with a nice gallery of thumbnails and captions that flow.
Note that I am using the pseudo-classes :focus, :hover and :active to display a red "border" around the images. This is to give a visual clue to users.

Special thanks go to:

  • Ted Drake for letting me use his photos of Paris.
  • Vicki Falkland for checking my grammar and spelling.

Please use this contact form to send feedback and report errors.