Counters are a big part of programming. They help keep tabs on loops by storing the number of times it’s been executed. Common variable names for increment counters are i
, j
and k
. Before the days of modern CSS, keeping track of things on the page was either done manually in the markup, or by using JavaScript to tally things up. These days are long gone as CSS has a well supported counter property that makes things easy.
Numbering Sections of a Page
To get started with counters, imagine you have a page that has multiple <section>
tags, each with it’s own heading <h2>
and content. That page may look something like this:
<section> <h2>Ratings</h2> Insert a table with reptile ratings on it... </section> <section> <h2>Alligators</h2> Insert awesome facts about alligators here... </section> <section> <h2>Turtles</h2> Insert interesting facts about turtles here... </section> <section> <h2>Snakes</h2> Insert sketchy facts about snakes here... </section>
If you wanted to number each <section>
you could simply prefix each <h2>
with the number right in the markup. While a great solution when you have a small fixed number of sections, things fall apart quickly when you have tens or even hundreds of sections. The complexity compounds quite quickly the moment you need to reorder the sections.
To alleviate this burden, we can use CSS counters. The first step to using CSS counters is to initialize a counter, which sets the value to zero 0
:
body { counter-reset: sections; }
For each section, we will want to increment the counter by 1
:
section { counter-increment: sections; }
To use the counter’s value, we can use the content
property to prepend the value to the heading h2
:
h2:before { content: counter(sections) ". "; }
Now we’ll have section headings like 1. Ratings
and 2. Alligators
. That’s not all, the counter is impervious to adding and removing new sections as well as reordering them!
Counting the Number of Rows in a Table
Counting the number of rows <tr>
in a <table>
is quite similar to how we added a numerical value to each section on the page. The big difference will be that we are only interested in the total value, and not the value for each row.
Before we can tally up the rows in a <table>
, we will need a <table>
to work with:
<table border="1" cellpadding="5"> <thead> <tr> <th>Reptile</th> <th>Rating</th> </tr> </thead> <tbody> <tr> <td>Alligator</td> <td>9001</td> </tr> <tr> <td>Turtle</td> <td>223</td> </tr> <tr> <td>Snake</td> <td>3.14</td> </tr> </tbody> <tfoot> <tr> <th>Rows</th> <th class="total"></th> </tr> </tfoot> </table>
Note the use of <thead>
, <tbody>
and <tfoot>
. While not necessary, by grouping the rows into sections, we can better target just the rows in the <tbody>
section and omit any rows in the header or footer.
Same as before, we will want to initiate a counter with a zero value:
body { counter-reset: rows; }
For each row <tr>
in the <tbody>
we shall increment the counter:
table tbody tr { counter-increment: rows; }
Finally, we will add the total number of rows, the final value of the counter, to the footer in the column aptly classed as .total
:
table .total:before { content: counter(rows); }
Now our <table>
will report on how many rows it contains. Adding or deleting rows to the markup will yield an updated total. This even works when using JavaScript to manipulate the DOM.
Conclusion
Even though we’re blurring the line between content and design, counters in CSS are extremely useful and in many cases can completely eliminate the need of introducing JavaScript to a page.
Want to see the code snippets on this page in action and play around with it on your own? Check out the code from this post on CodeSandbox.