仓库源文站点原文

Modern CSS gives us several tools for generating list markers, ranging from simple built-in bullets to fully customized counter algorithms. Developers often reach for list-style-type without realizing they can mix built-in marker styles, counters, or even define completely new numbering systems with @counter-style.

list-style-type

Only a few elements (<li> and <summary>) have a default value of display: list-item. However, the list-style-type property may be applied to any element whose display value is set to list-item. Moreover, because this property is inherited, it can be set on a parent element (commonly <ol> or <ul>) to make it apply to all list items.

Use list-style-type when one of the built-in list markers already does what you need. Examples of built-ins:

/* keyword value */
list-style-type: disc;

/* string value — the same marker for every item */
list-style-type: "**";

/* We will talk about it soon */
/* matching an @counter-style rule */
list-style-type: custom-counter-style;

This is the simplest way to get bullets or numbering without custom logic. MDN has a full list of built-ins.

counter() CSS function

Use CSS counters (counter-reset, counter-increment, counter()) when you want to custom numbering rules for arbitrary HTML structures—not only <ol> or <ul>.

The counter() function accepts up to two parameters. The first parameter is the <counter-name>. The optional second parameter is the <counter-style>.

The basic workflow is:

  1. Define and initialize a counter with counter-reset
  2. Increment it using counter-increment
  3. Output it in content using counter()
ul {
  counter-reset: count;
}
li {
  counter-increment: count;
}
li::before {
  content:
    "[" counter(count) "] == ["
    counter(count, lower-alpha) "]";
}

/* It will render as:
[1] == [a] xxxx
[2] == [b] yyyy
*/
.double-list {
  counter-reset: count -1;
}

.double-list li {
  counter-increment: count 2;
}

.double-list li::marker {
  content: counter(count, decimal) ") ";
}

/* It will render as:
1) Item 1
3) Item 2
5) Item 3
*/
section {
  counter-reset: sectionCounter;
}
h2::before {
  counter-increment: sectionCounter;
  content: "Section " counter(sectionCounter, lower-roman) ": ";
}

<section>
  <h2>Intro</h2>
  <h2>Usage</h2>
</section>
/* It will render as:
Section i: Intro
Section ii: Usage
*/
.level-1 {
  counter-reset: myLevel1;
}
.level-1 > .item {
  counter-increment: myLevel1;
}
.level-1 > .item::before {
  content: counter(myLevel1, decimal) ". ";
}

.level-2 {
  counter-reset: myLevel2;
}
.level-2 > .item {
  counter-increment: myLevel2;
}
.level-2 > .item::before {
  content: counter(myLevel2, lower-alpha) ") ";
}

/* It will render as:
1. Level 1 item
2. Level 1 item
   a) Level 2 item
   b) Level 2 item
3. Level 1 item
*/

@counter-style rule

Use @counter-style when you want to define a fully custom numbering system or bullets.

@counter-style checkmark {
  system: cyclic;
  symbols: "✔";
  suffix: " ";
}

ul {
  list-style-type: checkmark;
}

Check more examples here.

Besides use it directly in list-style-type, you can also use it with the counter() function to create custom counters.

@counter-style stars {
  system: numeric;
  symbols: "★" "★★" "★★★" "★★★★" "★★★★★";
}

ol {
  counter-reset: r;
}

li::before {
  counter-increment: r;
  content: counter(r, stars) " ";
}

/* 
Means each digit is shown using special “digit symbols”
digit 0 -> "★"
digit 1 -> "★★"
digit 2 -> "★★★" 
*/

Summary

CSS list markers are more powerful than most people expect.