Number nested ordered lists in HTML
Asked Answered
S

5

39

I have a nested ordered list.

<ol>
  <li>first</li>
  <li>second
  <ol>
    <li>second nested first element</li>
    <li>second nested secondelement</li>
    <li>second nested thirdelement</li>
  </ol>
  </li>
  <li>third</li>
  <li>fourth</li>
</ol>

Currently the nested elements start back from 1 again, e.g.

  1. first
  2. second
    1. second nested first element
    2. second nested second element
    3. second nested third element
  3. third
  4. fourth

What I want is for the second element to be numbered like this:

  1. first
  2. second

    2.1. second nested first element

    2.2. second nested second element

    2.3. second nested third element

  3. third
  4. fourth

Is there a way of doing this?

Scold answered 28/4, 2010 at 13:42 Comment(3)
What browsers do you need to support?Highlight
Is it going require extra code to do it e.g. Javascript or Ajax? I was hoping there was going to be a paramerter or css element I could just pass into the list. I see you can use the parameter type but this just changes the number type as far as I can seeScold
possible duplicate of Can ordered list produce result that looks like 1.1, 1.2, 1.3 (instead of just 1, 2, 3, ...) with css?Garlen
T
38

Here's an example which works in all browsers. The pure CSS approach works in the real browsers (i.e. everything but IE6/7) and the jQuery code is to cover the unsupported. It's in flavor of an SSCCE, you can just copy'n'paste'n'run it without changes.

<!doctype html>
<html lang="en">
    <head>
        <title>SO question 2729927</title>
        <script src="http://code.jquery.com/jquery-latest.min.js"></script>
        <script>
            $(document).ready(function() {
                if ($('ol:first').css('list-style-type') != 'none') { /* For IE6/7 only. */
                    $('ol ol').each(function(i, ol) {
                        ol = $(ol);
                        var level1 = ol.closest('li').index() + 1;
                        ol.children('li').each(function(i, li) {
                            li = $(li);
                            var level2 = level1 + '.' + (li.index() + 1);
                            li.prepend('<span>' + level2 + '</span>');
                        });
                    });
                }
            });
        </script>
        <style>
            html>/**/body ol { /* Won't be interpreted by IE6/7. */
                list-style-type: none;
                counter-reset: level1;
            }
            ol li:before {
                content: counter(level1) ". ";
                counter-increment: level1;
            }
            ol li ol {
                list-style-type: none;
                counter-reset: level2;
            }
            ol li ol li:before {
                content: counter(level1) "." counter(level2) " ";
                counter-increment: level2;
            }
            ol li span { /* For IE6/7. */
                margin: 0 5px 0 -25px;
            }
        </style>
    </head>
    <body>
        <ol>
            <li>first</li>
            <li>second
                <ol>
                    <li>second nested first element</li>
                    <li>second nested second element</li>
                    <li>second nested third element</li>
                </ol>
            </li>
            <li>third</li>
            <li>fourth</li>
        </ol>
    </body>
</html>
Transmittance answered 28/4, 2010 at 13:57 Comment(5)
can this solution be altered so that the styles are applied using JQuery? If so would this then work in all browsers?Scold
@John: OK, I added it. It however won't work on IE6/7 with JS disabled :)Transmittance
How do I make it work if I have more than 2 levels? Say, with 5 levels?Ducat
Ah, and it also doesn't work well with paragraphs. Say if you have multiple paragraphs in one list element. No <p> goodness, only <br /> works.Ducat
It'd be helpful to add a class to identify lists that require this special numbering, just to avoid potential conflicts. More levels could be accommodated with a different styling approach as illustrated below - I imagine the jQuery code could be reworked to use recursion so it could work with any number of levels, though it'd probably be wise to put in some form of cut off just in case.Price
B
35

I know it is late to reply, but I just found an example of doing that using CSS. Add this to you CSS section (or file):

ol.nested
{
    counter-reset: item
}
li.nested
{
    display: block
}
li.nested:before
{
    content: counters(item, ".") ". ";
    counter-increment: item
}

Here is an example of how your list code would look like:

<ol class="nested">
<li class="nested">item 1</li>
<li class="nested">item 2
    <ol class="nested">
        <li class="nested">subitem 1</li>
        <li class="nested">subitem 2</li>
    </ol></li>
<li class="nested">item 3</li>
</ol>

HTH

Brina answered 14/9, 2011 at 19:30 Comment(2)
Looks like the link is dead, but this example is also available from Opera as well: dev.opera.com/articles/view/…Price
Thanks, this is great! Far simpler than using jQuery! This solution has an advantage of interpreting multiple nests! 1 -> 1.1 -> 1.1.1 -> 1.1.1.1 Whereas, jQuery solution goes up to 1.1Duality
D
8

None of solutions on this page works correctly and universally for all levels and long (wrapped) paragraphs. It’s really tricky to achieve a consistent indentation due to variable size of marker (1., 1.2, 1.10, 1.10.5, …); it can’t be just “faked,” not even with a precomputed margin/padding for each possible indentation level.

I finally figured out a solution that actually works and doesn’t need any JavaScript.

It’s tested on Firefox 32, Chromium 37, IE 9 and Android Browser. Doesn't work on IE 7 and previous.

CSS:

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, ".") " ";
}

Example: example

Try it on jsFiddle, fork it on Gist.

Diagram answered 7/10, 2014 at 19:28 Comment(0)
C
0

This is not possible in pure HTML/CSS. See BalusC's answer for a great thinking-out-of-the-box solution. A list of numbering types can be found at w3schools, here.

The closest option I was able to find is use of the value attribute, from w3c, but the following markup

<ol>
    <li value="30">
        makes this list item number 30.
    </li>
    <li value="40">
        makes this list item number 40.
    </li>
    <li>
        makes this list item number 41.
    </li>
    <li value="2.1">
        makes this list item number ...
    </li>
    <li value="2-1">
        makes this list item number ...
    </li>
</ol>

produces a list numbered 30, 40, 41, 2 and 2.

As John already pointed out, your best bet is going to be scripting, in this situation.

Cystocarp answered 28/4, 2010 at 13:54 Comment(0)
H
0

Acctualy if you used sass/scss in you project for styling you can use mixin for this . For styling this nested list you need only two lines of sass code.

@import 'nested_list'
+nested_list('nested', 2)

<ol>
  <li>first</li>
  <li>second
      <ol class="nested-2">
          <li>second nested first element</li>
          <li>second nested secondelement</li>
          <li>second nested thirdelement</li>
      </ol>
  </li>
  <li>third</li>
  <li>fourth</li>
</ol>

Full example you can clone/watch from git repo or generated css on fidle

Herringbone answered 8/5, 2013 at 15:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.