Keywords: CSS Counters | Nested Lists | Ordered Lists
Abstract: This article explores how to use CSS counters to achieve hierarchical numbering formats (e.g., 1.1, 1.2, 1.3) for nested ordered lists, instead of traditional flat sequences. By analyzing the counter mechanism in W3C standards and providing detailed code examples, it explains the usage of counter-reset, counter-increment, and the counters() function. The paper also compares different implementation approaches, including improved solutions for handling long text wrapping and alignment issues, offering practical technical references for front-end developers.
Fundamentals of CSS Counters
In traditional HTML ordered lists, the list-style-type: decimal property only generates simple numeric sequences (1, 2, 3...), which cannot meet the requirements for hierarchical numbering in multi-level nesting. The CSS Counters mechanism provides a standardized solution for this need.
Counters are essentially CSS variables, initialized via counter-reset, incremented with counter-increment, and output in the content property using the counter() or counters() functions. Specifically, counters(item, ".") automatically concatenates values from multi-level counters, using the specified separator to form hierarchical numbers.
Standard Implementation Approach
According to W3C specifications, achieving nested list formats like "1.1", "1.2" requires the following CSS code:
ol {
counter-reset: item;
}
li {
display: block;
}
li:before {
content: counters(item, ".") " ";
counter-increment: item;
}Corresponding HTML structure example:
<ol>
<li>First level item
<ol>
<li>Second level sub-item</li>
<li>Second level sub-item</li>
</ol>
</li>
<li>First level item</li>
</ol>In this approach, counter-reset: item initializes the counter on each <ol> element, ensuring independent counting for nested lists. display: block converts list items to block-level elements for proper pseudo-element positioning. The li:before pseudo-element uses counters(item, ".") to output the current level path (e.g., "1.1") and increments the counter value via counter-increment.
Handling Long Text and Alignment Issues
The basic solution may encounter alignment problems with long text wrapping. An improved approach uses table layout to ensure stable alignment between numbers and content:
ol {
list-style-type: none;
counter-reset: item;
margin: 0;
padding: 0;
}
ol > li {
display: table;
counter-increment: item;
margin-bottom: 0.6em;
}
ol > li:before {
content: counters(item, ".") ". ";
display: table-cell;
padding-right: 0.6em;
}
li ol > li {
margin: 0;
}
li ol > li:before {
content: counters(item, ".") " ";
}This method creates a stable layout structure through display: table, with numbers right-aligned as table cells and content indented consistently during wrapping. padding-right controls the spacing between numbers and text, enhancing readability.
Alternative Absolute Positioning Solution
Another implementation uses absolute positioning to separate numbers from content:
ol {
counter-reset: item;
}
li {
display: block;
position: relative;
}
li:before {
content: counters(item, ".")".";
counter-increment: item;
position: absolute;
margin-right: 100%;
right: 10px;
}This approach absolutely positions numbers to the left of the content, with right: 10px controlling spacing to mimic the browser's default right-aligned effect, though attention to the parent container's positioning context is necessary.
Browser Compatibility and Best Practices
CSS counters are widely supported in modern browsers (IE8+, Firefox, Chrome, Safari). Developers should note:
- Ensure consistent counter names to avoid scope conflicts
- Use the same counter for nested lists to maintain continuous numbering
- Test layout stability with long text scenarios
- Consider accessibility to ensure clear semantic numbering
By appropriately selecting implementation methods, developers can create well-structured, visually consistent hierarchical lists, enhancing document professionalism and readability.