Html ordered list 1.1, 1.2 (Nested counters and scope) not working
HtmlCssHtml ListsHtml Problem Overview
I use nested counters and scope to create an ordered list:
ol {
counter-reset: item;
padding-left: 10px;
}
li {
display: block
}
li:before {
content: counters(item, ".") " ";
counter-increment: item
}
<ol>
<li>one</li>
<li>two</li>
<ol>
<li>two.one</li>
<li>two.two</li>
<li>two.three</li>
</ol>
<li>three</li>
<ol>
<li>three.one</li>
<li>three.two</li>
<ol>
<li>three.two.one</li>
<li>three.two.two</li>
</ol>
</ol>
<li>four</li>
</ol>
I expect the following outcome:
1. one
2. two
2.1. two.one
2.2. two.two
2.3. two.three
3. three
3.1 three.one
3.2 three.two
3.2.1 three.two.one
3.2.2 three.two.two
4. four
Instead, this is what I see (wrong numbering):
1. one
2. two
2.1. two.one
2.2. two.two
2.3. two.three
2.4 three <!-- this is where it goes wrong, when going back to the parent -->
2.1 three.one
2.2 three.two
2.2.1 three.two.one
2.2.2 three.two.two
2.3 four
I have no clue, does anyone see where it goes wrong?
Here is a JSFiddle: http://jsfiddle.net/qGCUk/2/
Html Solutions
Solution 1 - Html
Uncheck "normalize CSS" - http://jsfiddle.net/qGCUk/3/ The CSS reset used in that defaults all list margins and paddings to 0
UPDATE http://jsfiddle.net/qGCUk/4/ - you have to include your sub-lists in your main <li>
ol {
counter-reset: item
}
li {
display: block
}
li:before {
content: counters(item, ".") " ";
counter-increment: item
}
<ol>
<li>one</li>
<li>two
<ol>
<li>two.one</li>
<li>two.two</li>
<li>two.three</li>
</ol>
</li>
<li>three
<ol>
<li>three.one</li>
<li>three.two
<ol>
<li>three.two.one</li>
<li>three.two.two</li>
</ol>
</li>
</ol>
</li>
<li>four</li>
</ol>
Solution 2 - Html
Use this style to change only the nested lists:
ol {
counter-reset: item;
}
ol > li {
counter-increment: item;
}
ol ol > li {
display: block;
}
ol ol > li:before {
content: counters(item, ".") ". ";
margin-left: -20px;
}
Solution 3 - Html
Check this out :
Your issue seems to have been fixed.
What shows up for me (under Chrome and Mac OS X)
1. one
2. two
2.1. two.one
2.2. two.two
2.3. two.three
3. three
3.1 three.one
3.2 three.two
3.2.1 three.two.one
3.2.2 three.two.two
4. four
How I did it
Instead of :
<li>Item 1</li>
<li>Item 2</li>
<ol>
<li>Subitem 1</li>
<li>Subitem 2</li>
</ol>
Do :
<li>Item 1</li>
<li>Item 2
<ol>
<li>Subitem 1</li>
<li>Subitem 2</li>
</ol>
</li>
Solution 4 - Html
This is a great solution! With a few additional CSS rules you can format it just like an MS Word outline list with a hanging first line indent:
OL {
counter-reset: item;
}
LI {
display: block;
}
LI:before {
content: counters(item, ".") ".";
counter-increment: item;
padding-right:10px;
margin-left:-20px;
}
Solution 5 - Html
Keep it Simple!
This is a Simpler and Standard solution to increment the number and to retain the dot at the end.
Even if you get the CSS right, it will not work if your HTML is not correct. see below.
CSS
ol {
counter-reset: item;
}
ol li {
display: block;
}
ol li:before {
content: counters(item, ". ") ". ";
counter-increment: item;
}
SASS
ol {
counter-reset: item;
li {
display: block;
&:before {
content: counters(item, ". ") ". ";
counter-increment: item
}
}
}
HTML Parent Child
If you add the child make sure it is under the parent li
.
Will not work ✘
Notice the parent li
and the child ol li
are individual here, this will not work.
<ol>
<li>Parent 1</li> <!-- Parent has open and close li tags -->
<ol>
<li>Child</li>
</ol>
<li>Parent 2</li>
</ol>
Will work ✔
You need to place the ol li
child element inside parent li
. Notice the parent li
is hugging the child.
<ol>
<li>Parent 1 <!-- Parent open li tag -->
<ol>
<li>Child</li>
</ol>
</li> <!-- Parent close li tag -->
<li>Parent 2</li>
</ol>
Solution 6 - Html
I encountered similar problem recently. The fix is to set the display property of the li items in the ordered list to list-item, and not display block, and ensure that the display property of ol is not list-item. i.e
li { display: list-item;}
With this, the html parser sees all li as the list item and assign the appropriate value to it, and sees the ol, as an inline-block or block element based on your settings, and doesn't try to assign any count value to it.
Solution 7 - Html
Moshe's solution is great but the problem may still exist if you need to put the list inside a div
. (read: CSS counter-reset on nested list)
This style could prevent that issue:
ol > li {
counter-increment: item;
}
ol > li:first-child {
counter-reset: item;
}
ol ol > li {
display: block;
}
ol ol > li:before {
content: counters(item, ".") ". ";
margin-left: -20px;
}
<ol>
<li>list not nested in div</li>
</ol>
<hr>
<div>
<ol>
<li>nested in div</li>
<li>two
<ol>
<li>two.one</li>
<li>two.two</li>
<li>two.three</li>
</ol>
</li>
<li>three
<ol>
<li>three.one</li>
<li>three.two
<ol>
<li>three.two.one</li>
<li>three.two.two</li>
</ol>
</li>
</ol>
</li>
<li>four</li>
</ol>
</div>
You can also set the counter-reset on li:before
.
Solution 8 - Html
After going through other answers I came up with this, just apply class nested-counter-list
to root ol
tag:
sass code:
ol.nested-counter-list {
counter-reset: item;
li {
display: block;
&::before {
content: counters(item, ".") ". ";
counter-increment: item;
font-weight: bold;
}
}
ol {
counter-reset: item;
& > li {
display: block;
&::before {
content: counters(item, ".") " ";
counter-increment: item;
font-weight: bold;
}
}
}
}
css code:
ol.nested-counter-list {
counter-reset: item;
}
ol.nested-counter-list li {
display: block;
}
ol.nested-counter-list li::before {
content: counters(item, ".") ". ";
counter-increment: item;
font-weight: bold;
}
ol.nested-counter-list ol {
counter-reset: item;
}
ol.nested-counter-list ol > li {
display: block;
}
ol.nested-counter-list ol > li::before {
content: counters(item, ".") " ";
counter-increment: item;
font-weight: bold;
}
ol.nested-counter-list {
counter-reset: item;
}
ol.nested-counter-list li {
display: block;
}
ol.nested-counter-list li::before {
content: counters(item, ".") ". ";
counter-increment: item;
font-weight: bold;
}
ol.nested-counter-list ol {
counter-reset: item;
}
ol.nested-counter-list ol>li {
display: block;
}
ol.nested-counter-list ol>li::before {
content: counters(item, ".") " ";
counter-increment: item;
font-weight: bold;
}
<ol class="nested-counter-list">
<li>one</li>
<li>two
<ol>
<li>two.one</li>
<li>two.two</li>
<li>two.three</li>
</ol>
</li>
<li>three
<ol>
<li>three.one</li>
<li>three.two
<ol>
<li>three.two.one</li>
<li>three.two.two</li>
</ol>
</li>
</ol>
</li>
<li>four</li>
</ol>
And if you need trailing .
at the end of the nested list's counters use this:
ol.nested-counter-list {
counter-reset: item;
}
ol.nested-counter-list li {
display: block;
}
ol.nested-counter-list li::before {
content: counters(item, ".") ". ";
counter-increment: item;
font-weight: bold;
}
ol.nested-counter-list ol {
counter-reset: item;
}
<ol class="nested-counter-list">
<li>one</li>
<li>two
<ol>
<li>two.one</li>
<li>two.two</li>
<li>two.three</li>
</ol>
</li>
<li>three
<ol>
<li>three.one</li>
<li>three.two
<ol>
<li>three.two.one</li>
<li>three.two.two</li>
</ol>
</li>
</ol>
</li>
<li>four</li>
</ol>
Solution 9 - Html
Thank you everyone above for their answers!
As I needed RTL solution, I found out that this can solve it:
ol.nested-counter-list li {
display: block;
unicode-bidi: bidi-override;
}
So you would use any of the solution above, but also update the specific CSS selector for RTL cases.