20

Is it possible to create an ordered list like the following? I like this for a table of contents I'm creating.

  1. Into
  2. Section1
    2.1 SubSection1
    2.2 SubSection2
  3. Section2
    .....

I have the following but each subsection restarts from 1.

<ol>
    <li>
        <a href="#Lnk"></a>
    </li>
    <li>
        <a href="#Lnk"></a>
    </li>
    <ol>
        <li>
            <a href="#Lnk"></a>
        </li>
        <li>
            <a href="#Lnk"></a>
        </li>
    </ol>
</ol>

Thanks

bad_coder
  • 11,289
  • 20
  • 44
  • 72
Thomas Buckley
  • 5,836
  • 19
  • 62
  • 110

6 Answers6

18

This can indeed be done with pure CSS:

ol {
    counter-reset: item;
}

li {
    display: block;
}

li:before {
    content: counters(item, ".")" ";
    counter-increment: item;
}

Same example as a fiddle.

Davide Cannizzo
  • 2,826
  • 1
  • 29
  • 31
jasonkarns
  • 1,762
  • 2
  • 14
  • 17
  • 1
    I couldn't get this to work. Copying the last
      tag gave a number 2.3 at the top level instead of the expected 3.
    – pheon Apr 11 '19 at 17:36
  • 1
    @pheon that fiddle has a slight typo. `ol` can only have `li` children. Any nested `ol` must be wrapped within an `li`. Updated: http://jsfiddle.net/jasonkarns/6xkzv37e/ – jasonkarns Apr 26 '19 at 20:48
4

There's quite a number of jQuery plugins to generate a table of contents.

robasta
  • 4,621
  • 5
  • 35
  • 53
1

Have you seen this post: Number nested ordered lists in HTML

I don't think it can be done without using JS.

Community
  • 1
  • 1
wvp
  • 1,134
  • 5
  • 15
  • 28
1

This code leads to the desired output for me:

<ol>
  <li>
    <a href="#Lnk">foo</a>
  </li>
  <li>
    <a href="#Lnk">bar</a>
    <ol>
      <li>
        <a href="#Lnk">baz</a>
      </li>
      <li>
        <a href="#Lnk">qux</a>
      </li>
    </ol>
  </li>
  <li>
    <a href="#Lnk">alpha</a>
    <ol>
      <li>
        <a href="#Lnk">beta</a>
      </li>
      <li>
        <a href="#Lnk">gamma</a>
      </li>
    </ol>
  </li>
</ol>

CSS:

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

Fiddle: http://jsfiddle.net/Lepetere/evm8wyj5/1/

Peter
  • 621
  • 1
  • 6
  • 16
0

For myself I was not happy with existing solutions. So I created a solution with Python3 and BeautifulSoup.

The function take HTML source as string and looks for header tags (e.g. h1). In the next steps an id= is created for the header and also corresponding toc entry.

def generate_toc(html_out):
    """Create a table of content based on the header tags.
    
    The header tags are used to create and link the toc.
    The toc as place on top of the html output.
    
    Args:
        html_out(string): A string containing the html source.

    Returns:
        (string): The new string.
    """
    from bs4 import BeautifulSoup

    # the parser
    soup = BeautifulSoup(html_out, 'html.parser')

    # create and place the div element containing the toc
    toc_container = soup.new_tag('div', id='toc_container')
    first_body_child = soup.body.find_all(recursive=False)[0]
    first_body_child.insert_before(toc_container)
    # toc headline
    t = soup.new_tag('p', attrs={'class': 'toc_title'})
    t.string = 'Inhalt'
    toc_container.append(t)

    def _sub_create_anchor(h_tag):
        """Create a toc entry based on a header-tag.
        The result is a li-tag containing an a-tag.
        """
        # Create anchor
        anchor = uuid.uuid4()
        h_tag.attrs['id'] = anchor  # anchor to headline
        # toc entry for that anchor
        a = soup.new_tag('a', href=f'#{anchor}')      
        a.string = h_tag.string
        # add to toc
        li = soup.new_tag('li')
        li.append(a)
        return li

    # main ul-tag for the first level of the toc
    ul_tag = soup.new_tag('ul', attrs={'class': 'toc_list'})
    toc_container.append(ul_tag)

    # helper variables
    curr_level = 1
    ul_parents = [ul_tag]

    # header tags to look for
    h_tags_to_find = [f'h{i}' for i in range(1, 7)]  # 'h1' - 'h6'
    for header in soup.find_all(h_tags_to_find):
        next_level = int(header.name[1:])

        if curr_level < next_level:  # going downstairs
            # create sub ul-tag
            sub_ul_tag = soup.new_tag('ul', attrs={'class': 'toc_list'})
            # connect it with parent ul-tag
            ul_parents[-1].append(sub_ul_tag)
            # remember the sub-ul-tag
            ul_parents.append(sub_ul_tag)
        elif curr_level > next_level:  # going upstairs
            # go back to parent ul-tag
            ul_parents = ul_parents[:-1]

        curr_level = next_level

        # toc-entry as li-a-tag
        li_tag = _sub_create_anchor(header)
        # add to last ul-tag
        ul_parents[-1].append(li_tag)

    return soup.prettify(formatter='html5')

This is maybe not elegant in all of your use cases. Myself I use to put TOC's on top of HTML reports generated by data sciences routines (e.g. pandas).

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
buhtz
  • 10,774
  • 18
  • 76
  • 149
0
<h5>Table of contents:</h5> <ol> <li><a href="#t1">Types of home fruit drying machines</a></li> <li><a href="#t2" >Electric fruit drying machine</a></li> <li><a href="#t3">What fruits can you dry with an electric fruit drying machine?</a></li> < li><a href="#t4">Zagores Machine Electric Fruit Dryer</a></li> <li><a href="#t5">Buy Electric Fruit Dryer</a></ li> <li><a href="#t6">Gas fruit drying machine</a></li> <li><a href="#t7">Electric fruit drying machine price</a>< /li> <li><a href="#t8">FAQ</a></li> </ol>

. see this in: enter link description here

spammer
  • 3
  • 3
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Nov 29 '22 at 12:11