Image Captions Generated with CSS and JavaScript

For a online news article I used to update, one thing we’d always feature is an image of some CEO and present a caption to go with it. I was unsure of the ‘best’ way to display image captions. This is one of those things for which I wish there was a SimpleQuiz.

Which is the best way to display an image and its caption?

  1. <p>
    <img src="person.jpg" alt="person" /><br />
    This is a person
    </p>
  2. <div>
    <img src="person.jpg" alt="person" />
    <span>This is a person</span>
    </div>
  3. <img src="person.jpg" alt="person" />
    <p>This is a person</p>
  4. <table>
    <tr>
    	<td>
    		<img src="person.jpg" alt="person" />
    	</td>
    	<td>
    		This is a person
    	</td>
    </tr>
    </table>
  5. Make the caption part of the image.

I’m sure there are several other ways. When I received a new update for the newsletter that involved an image and a caption, I found myself checking previous issues to remember how I’d done it before so that I could be consistent. I had always wondered if there could be an easier way so that I wouldn’t have to remember. With the power of DOM Scripting, I can do just that.

I chose answer B above for the purposes of this demonstration, with some slight deviation. Here’s the picture I chose to work with:

I wanted my caption to be on the bottom of image, appearing as if it’s part of it, with a strip of color behind it for readability, but have the strip being somewhat transparent so that the part of the image that I’m covering could still be visible. The final result to look like this:

The only thing I want to put in the markup is the <img> tag.

<img src="dave.jpg" alt="" />

…but I know that I’ll have to give a tad more information for the DOM to work its magic. For one, I need to add a class. Another thing is the text to use as a caption. I could use the alt attribute for this, but instead I’m going to use the title attribute.

<img
  src="dave.jpg"
  alt=""
  class="captioned"
  title="Dave Letterman" />

And I want the DOM to create the caption for me. For the most part, I used example from choice B above, with some tweaks. The end markup to create this would look like this:

<div class="imgcontainer">
	<img
	  src="dave.jpg"
	  class="captioned"
	  alt=""
	  title="Dave Letterman">
	<div class="caption">Dave Letterman</div>
</div>

When thinking about how to write a script to accomplish this, it’s best to write out the steps in plain English:

  1. Look through all the images on the page.
  2. Check to see if the images have the class “captioned”.
  3. If so, take the title attribute value from the image, create a div with a class=caption and put that title attribute text within that div.
  4. Place that caption div immediately after the image.
  5. Wrap the img and the caption in a div together, giving that container div a class of “imgcontainter”.

Here’s the script I came up with. I call it ‘captionizeImages’.

function captionizeImages() {
  if (!document.getElementsByTagName) return false;
  if (!document.createElement) return false;
  var images = document.getElementsByTagName("img");
  if (images.length < 1) return false; 
  for (var i=0; i<images.length; i++) {
    if (images[i].className.indexOf("captioned") != -1) {
      var title = images[i].getAttribute("title");
      var divCaption = document.createElement("div");
      divCaption.className = "caption";
      var divCaption_text = document.createTextNode(title);
      divCaption.appendChild(divCaption_text);
      var divContainer = document.createElement("div");
      divContainer.className="imgcontainer";
      images[i].parentNode.insertBefore(divContainer,images[i]);
      divContainer.appendChild(images[i]);
      insertAfter(divCaption,images[i]);
    }
  }
}

And, of course, each of those elements need to be styled:

.imgcontainer {
	position:relative;
	float:left;
	}
.caption {
	font: normal 1em/1.3em arial;
	background:#fff;
	color:#000;
	position:absolute;
	bottom:0;
	left:0;
	text-align:center;
	width:100%;
	opacity:.75;
	filter:alpha(opacity=85);
	}

The .imgcontainer needs position:relative because the .caption div will need to be absolutely positioned relative to that container div. I had to float it left so that the div would wrap nice and snug around the img (with a float, the div expands all the way across the screen).

For the caption, I wanted to have a little transparency, which is where the opacity declaration comes in. For IE, I have to use filter:alpha(opacity=XX) instead of the opacity:.XX declaration.

View the example.