The Description List + CSS Counters: A More Semantic Ordered List

Creating an ordered list was likely one of the first things you learned how to do with HTML. But it's scope is a bit limiting. We can use the description list and CSS counters to give us more flexibility and control over our numbered content.

The <ol> Element

We've all used the <ol> element to create simple numbered lists, and I would imagine anyone reading this post is pretty familiar with the element and how to it's coded. But for the sake of this tutorial, let's look at the typical execution of an ordered list. Let's say we wanted to create a list of step-by-step instructions on how to brew coffee using a French press. The code and output might look something like this:


<h2>How To Brew French Press Coffee</h2>
<ol>
	<li>Grind Coffee</li>
	<li>Add to french press</li>
	<li>Add boiling wayer</li>
	<li>Slowly push down plunger</li>
	<li>Pour and enjoy!</li>
</ol>

See the Pen 14a31b073f38ea54be3a0d4edff652e7 by Travis Self (@selfpressed) on CodePen.

That's all well and good, but what if you or your client decide to add a short description to accompany each step in the instructions? You might think to do something along these lines:


<h2>How To Brew French Press Coffee</h2>
<ol>
  <li>Grind Coffee</li>
  <p>Add whole coffee beans to grinder. Grind coffee at coarse setting.</p>
  <li>Add to french press</li>
  <p>Use approx. two tablespoons per 8oz. of water.</p>
  <li>Add water</li>
  <p>Heat water to appropriate temperature and slowly add to french press.</p>
  <li>Start the plunge!</li>
  <p>Gently stir water, and let sit 3-5 minutes. Place lid on french press and slowly press down plunger.</p>
  <li>Pour and enjoy!</li>
</ol>

Although this gives us the result we're looking for, it does not fit the content model for the <ol> element. According to the W3C specification, the <ol> element can only contain one or more <li> elements. Now, theoretically we could just put our paragraph elements inside the <li> elements, but that leaves me with a bad taste in my mouth. It doesn't feel semantic. We need to find a better way to organize our content that still gives us the auto-number functionality that we get with the ordered list.

The Description List + CSS Counters

Once called the definition list in HTML4, the <dl> element has been repurposed in HTML5 and is now called the description list. This is an often misunderstood and under used element, but offers us a more semantic way to organize a list of elements where the <ul> and <ol> elements fall short. Here's the same instruction list from before, this time coded as a description list. The <li> element is replaced by the <dt> element (term or name of item), which is followed by the <dd> element (which describes the term).


<h2>How To Brew French Press Coffee</h2>
<dl>
  <dt>Grind Coffee</dt>
  <dd>Add whole coffee beans to grinder. Grind coffee at coarse setting.</dd>
  <dt>Add to french press</dt>
  <dd>Use approx. two tablespoons per 8oz. of water.</dd>
  <dt>Add water</dt>
  <dd>Heat water to appropriate temperature and slowly add to french press.</dd>
  <dt>Start the plunge!</dt>
  <dd>Gently stir water, and let sit 3-5 minutes. Place lid on french press and slowly press down plunger.</dd>
  <dt>Pour and enjoy!</dt>
</dl>

What's missing? It is no longer a numbered list. Here's where CSS counters come in. There are two properties under the CSS counter umbrella: the counter-reset and the counter-increment. These properties can be added to just about any element. The counter-reset property is added to the parent element of whatever element you'd like to auto-number. You're essentially taking whichever parent-child model you choose and giving it the same functionality of the <ol>-<li> model. For the sake of this example, we're going to add the counter-reset property to our <dl> element, and the <counter-increment> property to our <dt> element. Here's what it looks like:

If you look at the CSS tab in the example above, you'll see the counter properties in action. The value you assign to the counter-reset property is simply a name for your counter. In this case, I gave my counter-reset a value of "step", to represent each step of the instructions. The counter-increment is set to the same value that you set your counter-reset to. Now all we have to do is tell the CSS which element to start auto-numbering, and we achieve this by setting the value of the content property to counter([name of counter]). So in our example, we set the content property of the dt:before element to counter(step). We now have a functioning counter. I added some padding to the dt:before element as well to give some spacing between the number and the content.

Customize Your Counter

Unlike the <li> element, we have a lot more control over the appearance of numbers generated by CSS counters. That's because we can insert those numbers into any element we choose, applying whatever styles you so choose to it. And because the numbers are inserted via the content property, we can also add additional strings before or after the number. Take a look at the following example:

In the example above, we modify the dt:before psuedo-element to add some more styles to the numbers generated by our CSS counters. We also added some additional strings to the content property by bookending our counter(step) with the word "Step" and a ":", which automatically gets added to the front and back of each number in our list. We now have an end result that utilizes the <dl> element for a more semantic list on the backend, and uses CSS counters to give us a highly customizable numbered list that we can change just as easy as the rest of our styled elements. Visit the W3 Spec to view all the ways you can customize your CSS counters.

comments powered by Disqus