Automatic Figure Numbering with CSS Counters

Learn about CSS counters, the figure element and how to combine both for automatically numbering figures in a web page.

Automatic-Figure-Numbering-with-CSS-Counters

View demo Download source

When writing articles, blog posts, tutorials, magazine entries or anything else, you will often want to include some images, charts, photographs, or even videos and code snippets to illustrate your content.

That being said, you will most likely want to attach some kind of caption to these elements, and perhaps number them so your readers can keep track of your thoughts.

And that’s exactly what we are going to do in today’s tutorial: combining the usage of the <figure> element with CSS counters to make your inserted elements (especially images) sexy as hell!

The figure element

The <figure> element is intended to be used along with the <figcaption> element to mark up images, illustrations, photos, diagrams and code snippets among other things. Here is what the spec says about this element:

The figure element represents a unit of content, optionally with a caption, that is self-contained, that is typically referenced as a single unit from the main flow of the document, and that can be moved away from the main flow of the document without affecting the document’s meaning.

Here is the basic markup for a figure:

<figure>
	<img src="path/to/your/image.jpg" alt="" />
	<figcaption>Here is the legend for your image<figcaption>
</figure>

Here are a few notes regarding the figure element:

  • The <figcaption> element is optional
  • You can only have one <figcaption> element in a <figure> element
  • You can embed as many other elements as you want in a <figure> element
  • When dealing with an image, you can leave the alt attribute empty if you include a <figcaption> to prevent screen readers from reading twice the same content

For more information about the <figure> element, I recommend you this great article from HTML5Doctor. There is also this entry at Mozilla Developer Network and of course the official specification.

Examples

For example, if you want to show a snippet of code, you can do it this way with the <figure> element:

<figure>
	<code>body { background: white; }</code>
	<figcaption>Some illustrated code with figure<figcaption>
</figure>

Basically, instead of adding your images this way:


<img src="cute-kitty.jpg" alt="This is a cute kitty!" />

… you can do something like this:


<figure>
	<img src="cute-kitty.jpg" alt="" />
	<figcaption>This is a cute kitty!<figcaption>
<figure>

Browser support

The <figure> is part of the “new” HTML5 elements, which are not understood by a range of old browsers including Internet Explorer 8. Since you don’t want to make your layout explode because of this tutorial, I’d recommend you include a polyfill to support these elements.

The most known and used polyfill for HTML is html5shiv which you can embed directly from the Google CDN by adding this line into your files:

<!--[if IE lte 8]><script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->

Note, how we use IE-specific conditional comments to prevent other browsers and IE versions greater than 8 from loading this script.

If you wish to know the story behind the html5shiv polyfill, please read this wonderful blog post from Paul Irish.

CSS Counters

CSS Counters have to be one of the most unknown CSS properties in the whole range of properties there is. It makes automatic numbering possible exclusively through CSS, without the help of neither HTML nor JavaScript.

This module relies on two properties and one value:

  • counter-reset which is used to initialize and reset one or several counters
  • counter-increment which is used to increment one or several counters
  • counter() is a valid value for ::before and ::after pseudo-elements, accepting a counter name as parameter in order to display its value

Pretty straight forward, isn’t it? Basically, you initialize a counter with the name you want to the value you want (mostly 0) and you tell a given selector to increment this counter at each occurrence. This counter can then be displayed using CSS generated content and the style and location can be specified with the :before and :after pseudo-elements.

The most basic implementation of a CSS counter has to be this one:

/* 1. We initialize the counter */
body {
	counter-reset: myAwesomeCounter;
}

/* 2. We tell each occurrence of this element to increment the counter */
.myAwesomeElement {
	counter-increment: myAwesomeCounter;
}

/* 3. We display the value of the counter before the element */
.myAwesomeElement:before {
	content: counter(myAwesomeCounter);
}

Note: I lied when I said “2 properties and 1 value”, there is also a counters() value which is almost never used. Please refer to this entry at MDN for more information about it.

Example

Back to our case, shall we? We want to number our images so that they are prefixed by “Fig. 1 – …”, “Fig. 2 – …” and so on, right? Let’s do it simply.

.article {
	counter-reset: figures;
}

.figure {
	counter-increment: figures;
}

.figure figcaption:before {
	content: 'Fig. ' counter(figures) ' - ';
}

Those 3 lines of CSS are enough to number our figures automagically. Isn’t that awesome?

Wrapping everything

The basics

Now that we know how to use both the <figure> element and CSS Counters, it is time to make what we wanted to do: embellish our blog posts.

But before jumping into the code, wouldn’t it be cool if we could easily make floated or centered figures, just by adding a simple class? Sure, it would be. Let’s do this!

We will start by giving our figures some decent styles. Nothing too fancy, something simple and elegant enough to make a kind of frame to your images.

.figure {
	padding: 0.9em;
	border: 3px solid #f5bca8;
	background: #fff;
	margin: 0 auto 1em;
}

In order to horizontally center images and prevent them from breaking out of their container (the <figure> element), we need to add some rules to them (could as well be <video> or something else).

.figure img {
	margin: 0 auto;
	display: block;
	max-width: 100%;
}

Now the caption! We make it stand out a bit, change the typography and center it horizontally. But frankly the styling is up to you. Just remember a caption should be removed without too much hassle, so don’t write a wall of text.

.figure figcaption {
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 2px;
	font-size: 0.8em;
	padding: .5em;
	text-align: center;
	color: #fff;
	background: #f5bca8;
}

Numbering

Great, we still haven’t implemented the counter to number our figures. As we’ve seen in the previous section, it is very easy to do.

.article {
	counter-reset: figures;
}

.figure figcaption {
	counter-increment: figures;
}

.figure figcaption:before {
	content: 'Fig. ' counter(figures) ' - ';
}

If you don’t necessarily want to number your images, you can limit this to a given class on the parent element. Perhaps you’ll give your wrapper a .numbered-figures class so that it enables image numbering. Easy enough:

.numbered-figures 							{ counter-reset: figures; }
.numbered-figures .figure figcaption 		{ counter-increment: figures; }
.numbered-figures .figure figcaption:before { content: 'Fig. ' counter(figures) ' - '; }

Variations

We have the basics for our system, but we still haven’t set up a way to have floated figures across the page. We will then make two classes:

.figure-left {
	float: left;
	margin: 0 1em .5em 0;
	width: -webkit-min-content;
	width: -moz-min-content;
	width: min-content;
}

.figure-right {
	float: right;
	margin: 0 0 .5em 1em;
	width: -webkit-min-content;
	width: -moz-min-content;
	width: min-content;
}

For those of you who do not know min-content, it is a valid value for width, min-width, max-width, height, min-height and max-height among other properties include flexbox and grid layout.

In our case, we want the figure element to be as small as possible; basically, we want it to wrap around the image. Because <figure> is a block-level element, it stretches to the width of its parent (100%). We could set it to float: left or display: inline-block to make it collapse to the widest piece of content but if the caption happens to be wider than the image we have a problem.

We could hard code the width to the figure element depending on the image, but it is inflexible and non-responsive. That’s why we introduce the min-content value. To put it simple, it tells the <figure> element to reduce its width so that the image fits inside it perfectly even if the caption has to wrap.

This value is supported by Firefox 3+ with the -moz- prefix and Chrome 18+ with the -webkit- prefix. The unprefixed version is currently not supported by any browser but might be in the future so we leave it.

Non-supportive browsers behave as expected: no width is set, the floated <figure> element wraps around the widest element, either the image or the caption.

Note: there are other values similar to min-content like max-content, fit-content and available. Please refer to this entry at MDN or the working draft of CSS Intrinsic & Extrinsic Sizing Module Level 3for further information about these.

Last but not least, we need to change/remove the max-width value on images for floated figures. Either you want images to have their own size, and you need to set max-width to none, or you want to set a maximum width (which I recommend) and you define whatever you want:

.figure-right img,
.figure-left img {
	max-width: 300px; /* Adjust to suit your needs */
}

Small screens

To make sure floated figures don’t behave oddly on small screens, we need to override a couple of styles to make them full-width and horizontally centered. If you’re building your site using a mobile first approach, you’ll do it the other way but it doesn’t matter really.

@media (max-width: 767px) {
	.figure-left,
	.figure-right {
		float: none;
		margin: 0 0 1em 0;
		width: 100%;
	}

	.figure img {
		max-width: 100%;
	}
}

Usage

Using this is easy as a pie. Either you want an horizontally centered figure in which case you simply have to use the .figure class. Or — most likely — you want to float the figure either on the left or on the right in which case you have to use both the .figure class and a variation class (e.g .figure-left).


<figure class='figure'>
	<img src="path/to/your/image.jpg" alt="" />
	<figcaption>Here is the legend for your image<figcaption>
</figure>


<figure class='figure figure-left'>
	<img src="path/to/your/image.jpg" alt="" />
	<figcaption>Here is the legend for your image<figcaption>
</figure>


<figure class='figure figure-right'>
	<img src="path/to/your/image.jpg" alt="" />
	<figcaption>Here is the legend for your image<figcaption>
</figure>

Final words

That’s pretty much it guys, the only thing left to do is to implement this on your site. Please have a look at the associated demo to see what it looks like or see it live on my own site.

Thanks for reading and happy coding!

View demo Download source

Previous:
Next:

Tagged with:

I am a front-end developer from Grenoble (France) with a passion for HTML5 and CSS3. Plus, I'm a geek and a gamer. I am the author of Browserhacks and Wild Web Watch.

View all contributions by

Website: http://hugogiraudel.com

Related Articles

Receive our bi-weekly Collective or blog updates right in your inbox.

Which newsletter would you like to receive?

CSS Reference

Learn about all important CSS properties from the basics with our extensive and easy-to-read CSS Reference.

It doesn't matter if you are a beginner or intermediate, start learning CSS now.