Automatically numbering figures using CSS counters

You can use CSS Counters and the ::before pseudo selector to automatically label and number figures within a webpage.


For the first 13 years of my career I worked as a research scientist for the Defence Evaluation and Research Agency (DERA, an agency of the UK’s MoD). I worked on 3–5 year projects covering a wide range of subjects. Even though the projects varied, they did all have one thing in common, i.e. one of the deliverables was always a report, and much like the infamous TPS reports from Office Space, the DERA reports also had to adhere to a strict format.

One of those strict formats related to numbering, not just numbering of chapters, but sections, paragraphs, figures, and list items. Depending on how the document was structured, it was not unusual to have a list item with a number such as Don’t get me wrong, this convention was actually useful, if you were on page 50 and wanted to reference an item on page 5, the numbering made a lot of sense.

As useful as numbering was for those DERA reports, it’s not something I find myself missing when writing a blog post. But, I do still find myself numbering figures in blog posts, this is useful as I often reference the figures from within the body text.

Anyone who has written a long report that requires any form of numbering knows that it’s not something you should attempt to do manually—it has to be automated—otherwise you’ll find yourself updating all the following chapters/sections/paragraphs etc. each time you insert a new one into the middle of the document.


There’s no solution for this in HTML/CSS that’s as convenient as the numbering and cross-referencing that’s part of Microsoft Word, but, there is a CSS solution that can at least handle the numbering part (but not the cross-referencing), and that solution is based on CSS Counters.

CSS Counters are, in essence, variables maintained by CSS whose values may be incremented or decremented by CSS rules that track how many times they’re used.

— Source: mdn web docs

To see a full description of CSS Counters and how they can be used, visit the CSS Counters page over at mdn web docs. The use of CSS Counters below deals only with counting figures and displaying that count within the figure’s caption i.e. the figcaption HTML element.

Set the counter to zero

First, we define a counter called ‘figures’, and we set it to zero (it defaults to zero when reset), this goes in the body CSS declaration:

body {counter-reset: figures;}

Increment the counter

Then, we increment the counter for each figcaption element that’s in the page, this goes in the figcaption CSS declaration:

figcaption {counter-increment: figures;}

Display the current count

Lastly, we display the current count of figcaptions within the figcaption CSS declaration. We do this by using the ::before pseudo selector. We place the figcaption count between the text “Figure” and “.”, so we end up with something like “Figure 5.”:

figcaption::before {content: 'Figure ' counter(figures) '. ';}

Implementation example

The code below shows the CSS used on to display figcaptions, and the HTML used to generate figures 1 & 2.

figcaption {
  counter-increment: figures; /* count the number of fig captions */
  font-size: 80%;
  margin-top: 5px;
  padding-top: 8px;
  font-style: italic;
  border-top: 2px solid var(--accent);

figcaption::before {
  content: 'Figure ' counter(figures) '. '; /* display the figure number */
The CSS used to automatically number all figures.
  <figcaption>The CSS used to automatically number all figures.</figcaption>

  <figcaption>The HTML used to display figures 1 & 2.</figcaption>
The HTML used to display figures 1 & 2.

You’ll notice from above [fig. 2] that the figcaption HTML elements do NOT include the text “Figure 1.” or “Figure 2.”, yet they are both visible in the figures’ captions.

Issues with this solution

Although the solution described above provides an easy method for automatically numbering figures within a page (actually, across all figures on a site that share the same style sheet,) it does have a few drawbacks:


One of the main reasons for numbering figures is so they can easily be referenced from within the article body e.g. “as you can see in figure 5”. Although adding new figures into the article will not require you to manually update the figure numbers, you will still have to update any cross-references, as there’s no link between the figure number and the cross-reference.


Although this solution automatically adds “Figure #” in your figcaptions, it’s important to note that anything added via the ::before or ::after pseudo selectors is NOT guaranteed to be available for reading aloud by screen readers (if you try and select the figcaption text above you’ll notice that “Figure 1”. cannot be selected.) But, I’ve read a couple of articles recently (here and here) that seem to suggest that the majority of popular screen readers do in fact read ::before and ::after elements, even though they are not part of the DOM.

RSS aggregators e.g. Feedly, Inoreader etc.

RSS aggregators won’t be using your CSS to display the article content from your RSS feed, so anything added by your CSS isn’t going to appear when your articles are viewed in those apps.