Forcing the figcaption element to wrap to the width of an image using CSS only

by Mike Badgley on September 30, 2011

This article describes a CSS-based solution for creating a floated <figure> element that allows for a caption (<figcaption>) to be displayed beneath – constrained to the width of the image.

An example of a photo and captionThe example on the left is a fairly common design element, yet one that can be a bit of a pain to style if you want to keep things as fluid and flexible as possible.

There are many solutions out there, or course, but I’ve yet to see one that is non-restrictive and/or easy to implement. To often they rely on a JavaScript plugin or an inline style that forces the width of the container to match the width of the image contained within. On a small site this is fine, but when its a site that is going to be managed by a number of people with varying degrees of HTML/CSS skills, I think its important to keep things as simple as possible.

The solution I came up with is based on a Stack Overflow posting I read that has been modified to work on a wider range of browsers – including IE8 and IE9. As mentioned in the introduction, this is a CSS-only based solution.

For the markup, I utilize the new HTML5 <figure> and <figcaption> elements, which are perfectly suited for this type of UI element:

<figure>
	<img height="215" width="215" src="660799.jpg" />
	<figcaption>
		This is a sample caption that should not exceed the width of the image.
	</figcaption>
</figure>

Pretty simple stuff – with the only real item of note being the height and width attributes on the <img> tag. These are required – and really – should be used regardless so that the browser can ‘smartly’ load the image with the proper dimensions.

Taking this markup and floating it to the left or right as you would normally do with an image, it’s easy to see the problem your going to run into. The caption text is going to keep flowing irregardless of the width of the image. To correct this, we simple do the following:

figure {
	float: left;
	display: table;
	width: 87px;
}

Forcing the <figure> element to display as a table means that the content within will flow to the constraints (width) that is placed upon it. Remember back in the bad old days where you would often see a sidebar column sized at 1% so that it would only take up as much horizontal room as was required by the content within? This is the same sort of idea here.

The ‘table’ is being forced to a width of 87 pixels (a completely arbitrary number – I just happen to be a Penguins fan), but because the image inside of it has a width attribute set (in this case 215 pixels), it grows to accommodate the width of the content and as a result the caption ‘grows’ along with it.

A pretty nifty solution that works very well across all modern browsers I tested on – including IE8. Basically this will work on any browser that supports the display: table CSS property.

4 comments

Niiice! A really clever solution to a tiresomely tricky problem. Thanks for sharing.

by Mark Iliff on August 18, 2012 at 5:10 pm. #

Applying the max-width: 100% rule globally to all images means that they automatically shrink to fit the screen width, and I’m not going to give up that benefit. I want my sites to look good on mobile devices. See http://www.alistapart.com/articles/responsive-web-design. I’m rather put line breaks (br /) in my figcaptions, as much of a pain as that is.

by Michael McGinnis on March 20, 2012 at 11:57 am. #

Hi. Thanks for this! It works great in Firefox but I can’t seem to get it to work in IE, Safari or Chrome. In those browsers the image and caption display at a very reduced width. The reverse of what should happen, seems to be happening. Instead of the table growing to accommodate the image width, the image width is shrinking to accommodate the table width. Do you know why this might happen?

by Kim B on December 15, 2011 at 3:14 pm. #

The problem was due to the max-width: 100% rule that you are applying globally to all images. When I disabled that, the image (and caption) rendered as expected.

by Mike Badgley on December 15, 2011 at 9:17 pm. #