Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using CSS to auto-number nested sections

Say I have an HTML or XML document like this:

<body>
   <section>
      <h1>This should be numbered 1</h1>
      <section>
        <h1>This should be numbered 1.1</h1>
        <p>blah</p>
      </section>
      <section>
        <h1>This should be numbered 1.2</h1>
        <p>blah</p>
      </section>
   </section>
   <section>
      <h1>This should be numbered 2</h1>
      <section>
        <h1>This should be numbered 2.1</h1>
        <p>blah</p>
      </section>
   </section>
</body>

This is merely an illustrative example; in general, there can be any number of child-sections within a section, and sections can be nested to any depth.

Is it possible to use CSS (counters and generated content) to generate the desired section-number at the start of each section-title?

The only examples I've seen where this sort of thing works is with nested lists, but there you can attach 'counter-reset' to OL and 'counter-increment' to LI. Here, it seems like you need 'section' to both reset for its child-sections, and increment wrt its parent section, and attaching both of those to one element-name doesn't work.

like image 642
Michael Dyck Avatar asked Jul 27 '15 21:07

Michael Dyck


People also ask

How do I use automatic numbering in CSS?

Simple Numbering In the CSS we are going to do three key things: Initialize the counter on the parent div using counter-reset. Increment the counter value by 1 on the child div p using counter-increment. Add the counter variables before the div p content using the :before pseudo selector.

Can you number sections in HTML?

Section headings ( h1 to h6 elements) can be automatically numbered according to the document structure. If there is only one h1 element in the document, it is supposed to be the document title and it is not numbered.

How do I make a counter in CSS?

To use a counter it must first be initialized to a value with the counter-reset property. The counter's value can then be increased or decreased using counter-increment property. The current value of a counter is displayed using the counter() or counters() function, typically within a pseudo-element content property.

What is counter-reset in CSS?

The counter-reset CSS property resets a CSS counter to a given value. This property will create a new counter or reversed counter with the given name on the specified element. Normal counters have a default initial value of 0.


1 Answers

You should use CSS counters in this case.

Update solution (better). Finally, a little more flexible approach would be resetting counter on the body initially instead of section:first-child and also on any immediate next sibling of the h1.

body,
section h1 + * {
    counter-reset: section 0;
}

Updated solution. Turned out that my original solution is not very good as pointed in comments. Here is revised correct version which should work properly with arbitrary number of nested or sibling sections.

section:first-child,
section h1 + section {
    counter-reset: section 0;
}
section h1:before {
    counter-increment: section;
    content: counters(section, ".") " ";
}
<section>
    <h1>This should be numbered 1</h1>
    <section>
        <h1>This should be numbered 1.1</h1>
        <p>blah</p>
    </section>
    <section>
        <h1>This should be numbered 1.2</h1>
        <p>blah</p>
    </section>
    <section>
        <h1>This should be numbered 1.3</h1>
        <section>
            <h1>This should be numbered 1.3.1</h1>
            <p>blah</p>
        </section>
        <section>
            <h1>This should be numbered 1.3.2</h1>
            <p>blah</p>
        </section>
    </section>
    <section>
        <h1>This should be numbered 1.4</h1>
        <p>blah</p>
    </section>
</section>
<section>
    <h1>This should be numbered 2</h1>
    <section>
        <h1>This should be numbered 2.1</h1>
        <p>blah</p>
    </section>
    <section>
        <h1>This should be numbered 2.2</h1>
        <p>blah</p>
    </section>
</section>

Original (buggy). There is tricky part in this case: counter should increment for every subsequent section. This can be achieved with section + section selector:

section {
    counter-reset: section;
}
section + section {
    counter-increment: section;
}
section h1:before {
    counter-increment: section;
    content: counters(section, ".") " ";
}
<section>
    <h1>This should be numbered 1</h1>
    <section>
        <h1>This should be numbered 1.1</h1>
        <p>blah</p>
    </section>
    <section>
        <h1>This should be numbered 1.2</h1>
        <p>blah</p>
    </section>
</section>
<section>
    <h1>This should be numbered 2</h1>
    <section>
        <h1>This should be numbered 2.1</h1>
        <p>blah</p>
    </section>
</section>
like image 154
dfsq Avatar answered Oct 06 '22 09:10

dfsq