Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.

This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.

In Web design, it is very important to have an organized way to present data, so that users can clearly understand the data structure and content displayed on the site. Using an ordered list is an easy way to achieve an organized presentation of data.

If you need to control the style of ordered list numbers more deeply, you may feel you have to add more HTML DOM structure or JavaScript to do so. Fortunately, CSS counters make solving this problem much easier. In this article, I’ll focus on what CSS counters are and some use cases.

The problem with ordered lists

When you write an ordered list like this, the browser automatically prefixes the list item with a number

<ol>
  <li>My First Item</li>
  <li>My Second Item</li>
  <li>My Third Item</li>
</ol>
Copy the code

This looks good, but it doesn’t allow you to style numbers. If you need to decorate a list by putting the number in a circle, what do you do?

One way is to remove the list entirely and manually add the numbers yourself.

<div>
  <span>1</span> My First Item
</div>
<div>
  <span>2</span> My Second Item
</div>
<div>
  <span>3</span> My Third Item
</div>
Copy the code
div {
  margin-bottom:10px;
}
div span {
  display:inline-flex;
  align-items:center;
  justify-content:center;
  width:25px;
  height:25px;
  border-radius:50%;
  background-color:# 000;
  color:#fff;
}
Copy the code

This is exactly what we want to do, but there are some downsides. First, adding numbers manually is cumbersome. If you need to change a number, you have to change them one by one. In this case, you could use JavaScript to dynamically add tags to solve these problems, but this would add more nodes to the DOM, resulting in a large memory footprint.

In most cases, it is best to use CSS counters. Let’s see why.

Introduction to CSS Counters

CSS counters are web page scoped variables whose values can be changed using CSS rules.

First, set the counter with the counter-reset attribute. List-number is the variable name used here.

div.list {
  counter-reset: list-number;
}
Copy the code

Next, use the counter-increment attribute to increment the counter.

div.list div {
  counter-increment: list-number;
}
Copy the code

Now, the list-number variable is incremented by one each time the div.listdiv element appears. Finally, use the :before pseudo-element with the set content attribute and counter() function to display the numbers.

div.list div:before {
  content: counter(list-number);
}
Copy the code

Here’s the full code:

<div class="list">
  <div>My first item</div>
  <div>My second item</div>
  <div>My third item</div>
</div>
Copy the code
div.list {
  counter-reset: list-number;
}
/** We can use counter-increment **/ in the :before element
div.list div:before {
  counter-increment: list-number;
  content: counter(list-number);
}
Copy the code

Now we are not quite there yet. Let’s style the :before pseudo-element to make it look better.

div.list div:before {
  counter-increment: list-number;
  content: counter(list-number);
  
  margin-right: 10px;
  margin-bottom:10px;
  width:35px;
  height:35px;
  display:inline-flex;
  align-items:center;
  justify-content: center;
  font-size:16px;
  background-color:#d7385e;
  border-radius:50%;
  color:#fff;
}
Copy the code

Modify the starting number

By default, counter-reset sets the counter to 0. When the first counter-increment is called, it starts at 1. The initial value can be set by taking an integer as the second argument to the counter-reset function.

div.list {
  counter-reset: list-number 1;
}
Copy the code

If you want to start at 0, you can set the initial value to -1.

div.list {
  counter-reset: list-number -1;
}
Copy the code

Change the increment value

By default, counter-increment increments the value of the counter by one. Just like counter-reset, you can define the offset of the counter-increment property.

In this example, counter-reset sets the list-number to 0. Each time you call counterincrement, the list-number increment is 2, so you’ll see the list order is 2, 4, and 6.

div.list {
  counter-reset: list-number;
}
div.list div:before {
  counter-increment: list-number 2;
  // other styles
}
Copy the code

Counter format

The counter() function can take two arguments: counter-name and counter-format. For the second argument, you can use any valid list-type value, including:

  • decimal(e.g., 1, 2, 3…)
  • lower-latin(e.g., a, b, c…).
  • lower-roman(e.g., I, ii, iii…).

The default value is numeric.

For example, if you’re scientific like me, you can use lower-Greek for numbering values.

div.list div:before {
  counter-increment: list-number;
  content: counter(list-number, lower-greek);
  // ... other styles
}
Copy the code

Counter nesting

When using nested order lists, always display the numbers in this format:

If you need numeric numbers for sublist items (for example, 1.1), you can use CSS counters with counters() function.

<ol>
  <li>
     My First Item
    <ol>
      <li>My Nested First Item</li>
      <li>My Nested Second Item</li>
    </ol>
  </li>
  <li>My Second Item</li>
</ol>
Copy the code
ol {
  list-style-type:none;
  counter-reset:list;
}
ol li:before {
    counter-increment:list;
    content: counters(list, ".") ".";
}
Copy the code

Note that we are using the counters() function instead of the counter() function.

The second argument to the counters() function is the join string. It can also have a third parameter to format (for example, Greek or Roman numerals).

A nested counter with a title

Elements such as

,

are not nested in the document. They appear as different elements, but still represent a hierarchy. Here’s how to set a nested number in a title:

body {
  counter-reset:h1;
}
h1 {
  counter-reset:h2;
}
h1:before {
  counter-increment: h1;
  content: counter(h1) ".";
}
h2:before {
  counter-increment:h2;
  content: counter(h1) "." counter(h2) ".";
}
Copy the code

The < H2 > counter is reset each time a

is found.

The number obtained in the document is related to

.

Browser support

CSS counters have been widely supported in browsers since they were introduced with CSS2. While using the counter() function in properties outside of content is still experimental, you can execute all the examples covered in this tutorial without hesitation.

A simple challenge

Are you ready for a simple challenge involving CSS counters?

Use CSS counters to display 1 to 1000 and their Roman characters in 10 lines of code.

If you’re stumped, here’s how you can do it:

To create 1000 div elements, use the following.

for (var i = 0; i < 1000; i++) {
  document.body.appendChild( document.createElement("div")); }Copy the code

CSS counters:

body {
  counter-reset:number;
}
div:before {
  counter-increment:number;
  content: counter(number) "= >" counter(number, lower-roman);
}
Copy the code

conclusion

CSS counters are a little-known feature in CSS, but you’d be surprised how often they come in handy. In this tutorial, we discussed how and when to use CSS counters and showed some examples.

Here is a list of the attributes we used.

attribute usage
counter-reset Reset (or create) a given value counter (default 0)
counter-increment Incrementing the given counter with the given offset (default 1)
counter(counter-name, counter-format) Gets the value of the counter from the given format
counters(counter-name, counter-string, counter-format) Gets the value of the nested counter from the given format

CSS counters are cool though. One thing to understand, however, is that all counters are global. If you use them in a large project with many CSS files, you may not be able to find where they are created, reset, and increment. Don’t overuse them, and be sure to use counters with descriptive names to avoid conflicts.

Some practical examples

<! DOCTYPEhtml>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
  <title>CSS counter</title>
  <style>
    html {
      box-sizing: border-box;
      font-size: 62.5%;
    }

    *,
    *::before,
    *:after {
      box-sizing: inherit;
    }

    body {
      font-family: Rambla, sans-serif;
      font-size: 2rem;
      line-height: 1.5;
      color: #03c03c;
    }

    h1 {
      text-align: center;
    }

    .wrapper {
      margin: 0 auto;
      width: 85%;
      display: -webkit-box;
      display: -webkit-flex;
      display: -ms-flexbox;
      display: flex;
      -webkit-justify-content: space-around;
      -ms-flex-pack: distribute;
      justify-content: space-around;
    }

    @media (max-width: 1100px) {
      .wrapper {
        -webkit-box-orient: vertical;
        -webkit-box-direction: normal;
        -webkit-flex-direction: column;
        -ms-flex-direction: column;
        flex-direction: column;
        -webkit-box-align: center;
        -webkit-align-items: center;
        -ms-flex-align: center;
        align-items: center; }}ol {
      counter-reset: li;
      margin: 20px 0;
      padding-left: 0;
    }

    ol>li {
      position: relative;
      margin: 0 0 25px 2em;
      padding: 4px 8px 4px 20px;
      list-style: none;
    }

    ol>li::before {
      content: counter(li);
      counter-increment: li;
      position: absolute;
      top: -2px;
      left: -2em;
      width: 2em;
      margin-right: 8px;
      padding: 4px;
      font-weight: bold;
      text-align: center;
    }

    li ol.li ul {
      margin-top: 6px;
    }

    ol ol li:last-child {
      margin-bottom: 0;
    }

    .disc>li::before {
      color: white;
      background-color: #03c03c;
      border-radius: 50%;
    }

    .circle>li::before {
      color: #03c03c;
      border: solid 2px #03c03c;
      border-radius: 50%;
    }

    .angle>li::before {
      color: #03c03c;
      border-right: solid 3px #03c03c;
      border-bottom: solid 3px #03c03c;
    }

    .shadow>li::before {
      color: white;
      background: #03c03c;
      box-shadow: 5px 5px 0 0 greenyellow;
    }

    .rombo>li {
      margin-bottom: 25px;
    }

    .rombo>li::before {
      color: white;
      z-index: 2;
    }

    .rombo>li::after {
      position: absolute;
      top: -2px;
      left: -2em;
      width: 2em;
      margin-right: 8px;
      padding: 4px;
      background-color: #03c03c;
      height: 2em;
      -webkit-transform: rotate(45deg);
      -ms-transform: rotate(45deg);
      transform: rotate(45deg);
      content: ' ';
      z-index: 1;
    }

    .underline>li::before {
      border-bottom: solid 3px #03c03c;
    }
  </style>
</head>

<body>
  <h1>Styling Ordered List Numbers</h1>
  <div class="wrapper">
    <ol class="disc">
      <li>Tomato</li>
      <li>Cucumber</li>
      <li>Onion</li>
      <li>Pepper</li>
    </ol>
    <ol class="circle">
      <li>Tomato</li>
      <li>Cucumber</li>
      <li>Onion</li>
      <li>Pepper</li>
    </ol>
    <ol class="angle">
      <li>Tomato</li>
      <li>Cucumber</li>
      <li>Onion</li>
      <li>Pepper</li>
    </ol>
    <ol class="shadow">
      <li>Tomato</li>
      <li>Cucumber</li>
      <li>Onion</li>
      <li>Pepper</li>
    </ol>
    <ol class="rombo">
      <li>Tomato</li>
      <li>Cucumber</li>
      <li>Onion</li>
      <li>Pepper</li>
    </ol>
    <ol class="underline">
      <li>Tomato</li>
      <li>Cucumber</li>
      <li>Onion</li>
      <li>Pepper</li>
    </ol>
  </div>
</body>
</html>
Copy the code

More Excellent Cases

Css-tricks.com/custom-list…