Press enter to go to start of page

Cascading Stylesheets

Counters

Learning Outcomes

On completion of this lesson you will learn:

Go to top

Introduction

HTML provides us with a means of numbering lists of items by using the <ol></ol> element. The problem with this is that one cannot separate the numbers from the lines that they number.

If we wish to format the numbers separately we must use the CSS counter.

Go to top

A basic Counter Example

For our first example we shall start with a list of paragraphs that we want numbered. The HTML file is shown below.

Listing 1
                        <!doctype html>
                        <html lang="en">
                            <head>
                                <link href="Counters.css" rel="stylesheet" type="text/css">
                                <meta charset="utf-8">
                            </head>
                            <body>
                                <h3>House Rules</h3>
                                <p>Residents must leave building by 9:00 AM</p>
                                <p>Residents must return to building before 8:00 PM</p>
                                <p>No alcohol allowed in any part of the building</p>
                                <p>Lights out by 10:00 PM</p>   
                            </body>
                        </html>
                    

The code here is simple enough that there is no need to explain it. Without any styling it would render on a web page as in Fig 1 below.

A list of paragraphs without numbers
Fig 1: Raw text

Cross-referencing Fig 1 with Listing 1 we see that the four rules the residents must follow comprise of a paragraph each. Our aim is to style the paragraphs with a number that uniquely identifies each paragraph.

Listing 2 below show the CSS code for numbering the paragraphs.

Listing 2
                        body{
                            counter-reset: ruleCounter
                        }
                        p::before{
                            counter-increment:  ruleCounter;
                            content: counter(ruleCounter) ": ";
                        }
                    

At line 2 the counter-reset property creates a counter named ruleCounter and initialises it to zero. This starts off the counting process. If you are familiar with programming this is equivalent to creating and initialising a global variable.

Lines 4 to 7 is somewhat more complex. We shall begin with line 4. p and before are separated by a double colon. This means that before is a pseudo-elelennt that is attached to p.

As an element it can be styled like any other element you are familiar with. This rule is activated whenever the browser encounters a paragraph element.

Once rule is activated, two events occur:

When the second paragraph is encountered, the same sequence of events occur, except that now the value of ruleCounter Will be 2. Smilarly its value will be incremented to 3 and 4 respectively.

A list of numbered paragraphs
Fig 2: Paragraphs numbered using counter
Go to top

Using two Counters

In the example we have just completed we had a single <h3> heading followed by a list of paragraphs. In this case there was no rason for us to have more than one counter since we we had only one heading: 'House Rules'

Looking at Listing 3 below we have two level 3 headings at lines 8 and 13. If we have two Level 3 headings there is no reason why we should not have more headings at the same level. Therefore it is time that we put counters on the headings as well.

One other thing we have to be aware of is the numbering of the paragraphs. The paragraphs belonging to 'House Rules' which spans lines 9 to 12, would be numbered from 1 to 4 and the paragraphs belonging to 'Reasons for Eviction' should be numbered from 1 to 3.

Simply put, we need to reset the paragraph counter half way through the operation.

Listing 3
                        <!doctype html>
                        <html lang="en">
                            <head>
                                <link href="Counters.css" rel="stylesheet" type="text/css">
                                <meta charset="utf-8">
                            </head>
                            <body>
                                <h3>House Rules</h3>
                                <p>Residents must leave building by 9:00 AM</p>
                                <p>Residents must return to building before 8:00 PM</p>
                                <p>No alcohol allowed in any part of the building</p>
                                <p>Lights out by 10:00 PM</p>
                                <h3>Reasons for Eviction</h3>
                                <p>Alcohol in room</p>
                                <p>Allowing in strangers</p>
                                <p>Lights on after 10:00 PM</p>
                            </body>
                        </html>
                    

In order to be able to count the <h3> and the <p> levels we need two counters. In the previous example we had a counter for the <p> elements named ruleCounter and so we will carry this counter with us into the current version.

We also need to count the <h3> occurrences. For this we shall use a counter named h3Counter.

Looking at Listing 3 we see that h3 is the top level group and that p is a subgroup of it. This means that the paragraphs in lines 9 to 12 will be numbered numerically starting at 1. The paragraphs at lines 14 to 16 should be numbered also starting at 1 since they belong to a different group. This means that the counter ruleCounter needs to be reset back to zero at this point.

Listing 4 below shows us how this is done.

Listing 4
                        body{
                            counter-reset:  h3Counter ;
                        }
                        h3{
                            counter-reset: ruleCounter;
                        }
                        h3::before{
                            counter-increment: h3Counter;
                            content: counter(h3Counter) " ";
                        }
                        p::before{
                            counter-increment:  ruleCounter;
                            content: counter(ruleCounter) ": " ;
                        }
                    

At line 2 h3Counter is initialised to zero. This is done at body level since this counter does not need to be reset.

At line 5 the variable ruleCounter is reset to zero. This occurs at h3 level. Since the h3 tag occurs at lines 8 and 13, ruldCounter will be reset to zerro at those two points, The result of this is that lines 9 and 14 will will start counting at 1.

A list of numbered paragraphs using two counting levels
Fig 3: Paragraphs grouped on two levels

Here we see that the h3 groups are numbered from from 1 to 2 at the top level, while the paragraphs are numbered starting at 1 within each group.

Go to top

Styling the counters

We shall conclude this lesson with a few suggestions for styling or list. The great advantage of using counters instead of the <ol> is that you can style the line numbers and the text separately. This is because the line numbers are stored in the ::before pseudo-element. It has both width and height properties and therefore lends itself to a wide range of styling possibilities.

Below is the modified CSS file which now contains styling code.

Listing 5
                        body{
                            counter-reset:  h3Counter ;
                            background-color: orange;
                            font-weight: bold;
                            color: #008
                        }
                        h3{
                            counter-reset: ruleCounter;
                        }
                        h3::before{
                            counter-increment: h3Counter;
                            content: counter(h3Counter) " ";
                            margin-right: 10px;
                            margin-bottom:10px;
                            width:45px;
                            height:45px;
                            display:inline-flex;
                            align-items:center;
                            justify-content: center;
                            font-size:1.5rem;
                            font-weight: bold;
                            background-color:#008;
                            border-radius:50%;
                            color:beige;
                            border: medium solid black;
                        }
                        p::before{
                            counter-increment:  ruleCounter;
                            content: counter(ruleCounter);
                            margin-right: 10px;
                            margin-bottom:10px;
                            width:35px;
                            height:35px;
                            display:inline-flex;
                            align-items:center;
                            justify-content: center;
                            font-size:1rem;
                            font-weight: bold;
                            background-color:beige;
                            border-radius:50%;
                            color:#008;
                            border: medium solid #008;
                        }
                    

We shall not discuss the modified CSS file above as the extra code we added is purely decorative and therefore should be familiar to you by now.

A styled list
Fig 3: Nested lists with each level styled differently

The above image show what the two level list looks like after being styled according to Listing 5.

Go to top