Michael Dyck
Michael Dyck

Reputation: 2458

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.

Upvotes: 10

Views: 701

Answers (1)

dfsq
dfsq

Reputation: 193301

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>

Upvotes: 14

Related Questions