Captions over images
This is my response to Chris Coyier's screencast titled jQuery Part 3 – Image Title Plugin which I watched a couple of days ago. Something didn't sit right with me at the time, and I've now worked out what it was: JavaScript is not required!
I'll present a JavaScript-free approach for displaying captions over images that uses truly meaningful markup.
So what is meaningful markup for images and image captions? This is a debated issue, but I believe the definition list to be the most appropriate element at our disposal. While an image is clearly not a "term", a caption does describe an image, just as a definition describes a term. Meaningful markup for an image and its caption should look something like the following:
<dl> <dt><img src="images/paris.jpg" alt="View from Notre Dame de Paris" /></dt> <dd>View from Notre Dame de Paris</dd> </dl>
Ideally, images appearing one after the other should belong to the same definition list.
My aim was to achieve a result similar to Chris's image title plugin demo simply by styling a definition list containing images and their captions. In the end, I was forced to abandon the ideal of using a single definition list for multiple images and captions: the nature of CSS positioning dictates that each image–caption pair reside in its own element. The final markup, however, is still quite clean:
<dl class="captioned-image"> <dt><img src="images/paris.jpg" alt="View from Notre Dame de Paris" /></dt> <dd><span>View from Notre Dame de Paris</span></dd> </dl>
Additional markup required:
- Each definition list must have a class name of captioned-image applied
- Each caption must be wrapped in a span element (captions to appear on multiple lines require multiple span elements)
Check out the captions over images demo to see the approach in action. The CSS responsible for the appearance of the captions is as follows:
dl.captioned-image { position: relative; margin: 1em 0; } dl.captioned-image dt img { display: block; } dl.captioned-image dd { position: absolute; left: 0; bottom: 1.25em; font: bold 2em/1.25em Helvetica, sans-serif; } dl.captioned-image.top dd { top: 1.25em; } dl.captioned-image dd span { display: block; float: left; clear: both; background: #000; background: rgba(0, 0, 0, 0.7); padding: 0.25em 0.5em; color: #fff; }
I set out to display captions over images without the use of JavaScript while keeping meaningless markup to a minimum. Have I succeeded, do you think?
Possibly related posts
- Prototype image slider
- Ridding markup of textual decoration
- CSS fixed-position headers
- CSS image switcher (done the right way)
- JavaScript date and time localization
Comments
Wow! Dude, this is probably one of the coolest ways to get this done without JS.
Thanks for sharing!
Not a problem, David. It's great to see that I'm not the only one who loves to make content look great without compromising the purity of the markup. :)
Hi David, I really like this approach using a minimalist code practice, while also staying away from jquery if it is not absolutely needed. For one thing, I am really a novice designer, but I am striving for standards and to try and learn as much as possible as well along the way. Can this technique be used for an image slider, seeing how I am already using an "Unordered List" to do so?
Thank you, you and Chris C are both, web design heroes to me.
Shane
Hi Shane. I'm pleased to hear that you found this approach useful. If you point me in the direction of your image slider I'll have a look to see whether captions could be applied in the same way.
Thanks David,
This is the code for the slider I am using, or more specific the website that features the code that I am using, seeing how javascript seems to be beyond my comprehension at this point in time lol.
http://cssglobe.com/post/4004/easy-slider-15-the-easiest-jquery-plugin-for-sliding
Thanks again,
Shane
My understanding is that Easy Slider requires images to appear inside an unordered list. I've provided an example of an image slider that accepts the definition lists we know and love in a post titled Prototype image slider.
Wow thanks David, that could be just the solution I am looking for. I'll check it out later on today.
Shane
Hi David,
I like this approach and would definitely use it for an image gallery.
However, a large portion of the sliders I've come across are for featured content i.e posts on a blog and, in that instance I think the h2 would be my preferred choice.
Thanks for sharing.
Nice tut, but it doesn't work in IE 8. The text doesn't have any background, the position is perfect. Is it possible to come up with a variation that doesn't require multiple spans e.g Text 1 Text 2, as it would be a pain to draw content from existing sources. If you could point me in a direction that does or help me it would be very appreciated.
Thanks for the elegant approach!
IE8 doesn't support RGBa (RGB with alpha transparency), but I'm surprised to hear that it doesn't apply the fallback rule (background-color: #000). Browsers are supposed to ignore rules they don't understand.
To accommodate IE8, repeating a 1x1 semitransparent "image" should do the trick:
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQI12NgYGDYDAAAuAC0TCbBxgAAAABJRU5ErkJggg==) repeat;
The spans are required to faithfully mimic the visual style Chris employed – that is, to have each caption's background shrink-wrap its text, even if its text spans more than one line.
If you are happy with rectangular caption backgrounds, or have short captions which will should fit on one line, you can do away with the spans entirely – just apply the rules currently applied to the span elements to the dds directly. I've played around with this in Safari's Web Inspector and it works well.
Finally, keep in mind that I believe Chris intended this effect to be applied by hand. If you're dealing with existing or user-generated content it may be best to display captions in a more traditional manner.
Hey David, really nice work.
I've used it on my site (http://bretteveleigh.co.uk/), but I'm wondering why the boxes aren't aligning completely to the left. I've had to set the dl.captioned-image.top dd to left: -30px; to get it close to the left side.
Any ideas why it's not behaving? I'm sure I've done something wrong somewhere…
Thanks -Brett
You appear to be fighting against default browser styling, Brett. In Safari and Chrome, at least, I see:
dd { /* user agent style sheet */
-webkit-margin-start: 40px;
display: block;
}
If you include margin: 0 in dl.captioned-image dd you'll find that your
top and left offsets behave as expected. Safari and Chrome both expose the
WebKit Web Inspector which is incredibly useful in situations such as this.
If you're a Firefox user you should install Firebug.
Ah, thank you.
I use Opera as my main browser which might explain it. There's no way I would have found this, I'll be sure you check for it in future though.
Thanks
FANTASTIC!! I spent hours last night looking for a solution for captions over images that could be resized according to the div. This is the only thing that actually works with a minimal amount of code. Nice job and thank you!!
Thanks for your comment, Ken. I'm pleased you found the post helpful. I feel another post on definition lists brewing. :)
Very very nice.. could you see a way of the captions disappearing on rollover or some effect like that?
That turns out to be trivial, Tim. :)
dl.captioned-image dt:hover+dd { display: none; }
Ok, I'm hoping this is another trivial one. How about the reverse of what Tim was asking for? Display caption on hover only. I tried the following with no luck.
dl.captioned-image dt:link+dd { display:none; }
dl.captioned-image dt:hover+dd { display:block; }
Hopefully this is another trivial one. How about the reverse of what Tim requested. Hide the caption until onhover. I took a stab at it but struck out.
dl.captioned-image dt:link+dd { display:none;} dl.captioned-image dt:hover+dd {display:block; }
You weren't far from the solution, Ken.
dl.captioned-image dd { display: none; }
dl.captioned-image dd:hover,
dl.captioned-image dt:hover+dd { display: block; }
Why two :hover states? Initially the dd is hidden, but when one hovers over the image the dd becomes visible and the dt:hover selector no longer matches. Without the dd:hover selector, flashing can occur when one moves the cursor over a caption.
Very cool once again David. I took it to the next level with a border, etc.
dl.captioned-image dd span { display:block; float:left; clear:both; background:#FBDF78; border:#B23713 5px solid; background:rgba(0, 0, 0, 0.7); padding:0.25em 0.5em; color:#B23713; }
I go the idea here and I'm assuming that they're using java or jquery. Check out Top Stories on the right: http://news.yahoo.com/s/ap/20110408/ap_en_ot/us_people_clapton_marsalis
Hi David. Would you know how to center the text over the image?
The absolute positioning makes things tricky. Here are some things you could play around with:
- setting
right: 0ondl.captioned-image dd - setting
text-align: centerondl.captioned-image dd - removing
float: leftfromdl.captioned-image dd span - adding
margin: 0 autotodl.captioned-image dd span - using
line-heightto affect the text's vertical position