Nested ordered lists with counters, driving me nuts!

Hi guys,

First time poster here, so please be gentle. I am hoping one of you CSS gurus can help me out.

I have been struggling with creating a nested ordered list, numbered correctly with decimals, using CSS 2.1 counters. To appear like so:

[B]1. First Sentence
2. Second Sentence

2.1 Sub Sentence

2.2 Sub Sentence

  1. Third Sentence[/B]

Without a class I have been coding it up like so ,which works fine, but will obviously apply to all OLs across my site:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
<style type="text/css">
ol{
	counter-reset: listing ;
}
li {
	display: block ;
}
li:before {
	content: counters(listing, ".") " ";
	counter-increment: listing ;
}
</style>
</head>

<body>
<ol>
  <li>First Sentence</li>
  <li>Second Sentence</span>
    <ol>
      <li>Sub-Sentence</li>
      <li>Sub-Sentence</li>
    </ol>
  </li>
  <li>Third Sentence</li>
</ol>
</body>
</html>

When I apply a class to my code, it suddenly becomes like so:

[B]1. First Sentence
2. Second Sentence

3. Sub Sentence

4. Sub Sentence

  1. Third Sentence[/B]

I have found it a struggle to get got my head around the concept of the counters, and then I finally got it right in my mind, before assigning it a class, but as soon as I go to give it a class, it breaks!

Quite simply, according to my code below, I am trying to get the ordered list classed as ‘listing’ to number correctly with counters, without affecting all of the other ordered lists on my website.

My code at the moment is as below:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Sample Page - Ordered List</title>
<style type="text/css">
ol.listing {
	counter-reset: list;
}
ol.listing li {
	display: block;
}
ol.listing li:before {
	counter-increment: list;
	content: counters(list, ".") " ";
}
</style>
</head>

<body>
<ol class="listing">
  <li>First Sentence</li>
  <li>Second Sentence</span>
    <ol>
      <li>Sub-Sentence</li>
      <li>Sub-Sentence</li>
    </ol>
  </li>
  <li>Third Sentence</li>
</ol>
</body>
</html>

I am not sure if this is explained too well, but I hope someone knows what I mean. Any ideas where I am going wrong?:shifty:

P.S. Browser quirks not important (i.e. I know this will not work on pre-IE7 etc)

Hi Carlos, Welcome to SitePoint :slight_smile:

As far as the example you are aiming for, it can be as simple as this while using the default margins and paddings that the browsers will apply.

http://www.w3.org/TR/CSS2/generate.html#scope

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
 "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>OL Counter-Reset</title>

<style type="text/css">
ol { counter-reset: item }
li { display: block }
li:before { content: counters(item, ".") " "; counter-increment: item }

</style>

</head>
<body>

<ol>
    <li>First Sentence</li>
    <li>Second Sentence
        <ol>
            <li>Sub-Sentence</li>
            <li>Sub-Sentence</li>
        </ol>
    </li>
    <li>Third Sentence</li>
</ol>

</body>
</html>

Now if you want to start styling the nested lists it’s just a matter of resetting as you go down the tree. :wink:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Nested List with Counter-Reset</title>
 
<style type="text/css">
body {
    margin: 0;
    padding: 0;
    font: 100%/1.2em arial, helvetica, sans-serif;
}
ol {
    width: 20em;
    margin: 2em;
    padding: .5em;
    background: #EEF;
    list-style: none;
    counter-reset: item;
}
ol li {
    display: block
    margin: .5em 0;
    padding-left: 2em;
}
ol li:before {
    display: inline-block; 
    margin-left: -2em;
    margin-right: .5em;
    text-align: center;
    content: counters(item, ".") ".";
    counter-increment: item;
    background: cyan;
}
ol ol {/*resets from parent OL*/
    width: auto;
    margin: 0;
    padding: .5em 0;
    background: #0F0;
}
ol li li:before {/*remove the trailing period*/
    content: counters(item, ".") " ";
    background: hotpink;
}
ol ol ol {
    padding: .5em 0 0;
}
ol li li {
    background: #FFF;
}
ol li li li{
    background: yellow;
}
ol li li li:before {/*target third level*/
    background: orange;
}
</style>
 
</head>
<body>
 
<ol>
    <li>First Sentence</li>
    <li>Second Sentence
        <ol>
            <li>Sub-Sentence</li>
            <li>Sub-Sentence</li>
            <li>Sub-Sentence
                <ol>
                    <li>Sub-Sentence</li>
                    <li>Sub-Sentence</li>
                    <li>Sub-Sentence</li>
                </ol>
            </li>
        </ol>
    </li>
    <li>Third Sentence</li>
</ol>


</body>
</html>

Wow… you are a genius. This is exactly what I was after. I was hoping the counters specification in CSS 2 would be a little easier and intuitive to implement, as it does seem a little clunky.

I am now playing with your code to allow the parent OL to be declared as a different class from the standard OLs on the rest of the site. I do not want the counters to be rolled out on my global stylesheet for all OLs. It does seem to break once a class is declared though, but I will keep tinkering!

This is all taking a little bit of grey matter to understand, but with help from kind people such as yourself, I am getting there slowly. Thanks again!!:smiley:

TBH, I don’t have Counters & Numbering mastered yet either.
I just fumble my way through them when the need arises.

Glad you found it helpful just the same. :slight_smile:

It does seem to break once a class is declared though, but I will keep tinkering!

There is a straggling </span> in the code you posted. I do see what you are saying about the classes killing it though. I’ll look into that and see if I can make anything out of it.

Weird thing is… whilst tinkering, I found that this works perfectly:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
<style type="text/css">

ol.listing{
	counter-reset: test;
}

ol.listing li{
	display: block ;
}

ol.listing li:before {
	content: counters(test, ".") " "; 	
	counter-increment: test ;
}
</style>

</head>

<body>
<ol class="listing">
	<li>This is the first item</li>
	<li>This is the second</li>
        <ol class="listing">
            <li>This is a test indented item</li>
            <li>And another</li>
            <ol class="listing">
                <li>And a third indented test</li>
                <li>And another</li>
            </ol>
        </ol>
	<li>This is the third</li>
</ol>
</body>
</html>

But I cannot use a new class for every nested OL as I am coding the stylesheet for a huge set of pages that already exist, with the class only being declared for the parent OL in all of them. Unless I want to go back though all of the pages and code in the new class declarations for every nested list. :eek:

Right, you were taking care of the nested UL with that same class.
It seems that the styles only inherit in that case or when they are left generic.

The only other thing I could suggest as a last resort would be to wrap a div around it. That will allow you to style them separately without setting classes on the nested lists.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
 "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Sample Page - Ordered List</title>
<style type="text/css">
ol {
    margin:20px 5px;
    padding:0 0 0 40px;
}
ol ol {margin:10px;}

/*--- div class OL --*/
div.counter {
    width:300px;
    background: lime;
}
.counter ol {
    margin:5px;
    padding:5px 5px 5px 10px;
    counter-reset: item;
}
.counter ol li {
    display: block;
}
.counter ol li:before {
    counter-increment: item;
    content: counters(item, ".") " ";
}
</style>
</head>
 
<body>
<div class="counter">
    <ol>
        <li>First Sentence</li>
        <li>Second Sentence
            <ol>
                <li>Sub-Sentence</li>
                <li>Sub-Sentence</li>
            </ol>
        </li>
        <li>Third Sentence</li>
    </ol>
</div>

<ol>
    <li>First Sentence</li>
    <li>Second Sentence
        <ol>
            <li>Sub-Sentence</li>
            <li>Sub-Sentence</li>
        </ol>
    </li>
    <li>Third Sentence</li>
</ol>

</body>
</html>