10

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.

Michael Dyck
  • 2,153
  • 1
  • 14
  • 18
  • take a look at CSS https://developer.mozilla.org/en/search?q=counter . it is the typical use of that rule :) . then use selectors like > to filter elements/childs – G-Cyrillus Jul 27 '15 at 21:34

2 Answers2

14

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>
dfsq
  • 191,768
  • 25
  • 236
  • 258
  • Although this works for the specific example, it's not a general solution. Specifically, if the body (or any section) contains more than 2 child-sections, the ones after the second will all have the same label as the second ('2' or 'n.2' or 'n.n.2', etc). I've edited the problem statement to clarify that the section-tree can be arbitrarily wide as well as arbitrarily deep. – Michael Dyck Jul 28 '15 at 13:55
  • Hm, let me check for this. – dfsq Jul 28 '15 at 14:44
  • @MichaelDyck Check updated solution, that should work better. – dfsq Jul 28 '15 at 16:41
  • Yes, better. I needed to make two adjustments: (1) Re the selector `section:first-child`, I gather it's meant to only select "section 1". However, if there's some frontmatter before "section 1", the selector won't select anything, which will throw off all the section-numbering. Instead, the selector `body` works better. (2) Re the selector `section h1 + section`, if a section (e.g. 1.3) has an intro paragraph before its first child-section (e.g. 1.3.1), then the selector fails, which again throws off the numbering. Instead, `section h1 + *` avoids this problem. ... – Michael Dyck Jul 29 '15 at 03:13
  • ... I realize that neither of these cases showed up in the original example, so I don't fault you for that. And your answer got me most of the way to the solution, so you get the check mark. But if you make the above changes in your answer, that may help people with the same problem in the future. – Michael Dyck Jul 29 '15 at 03:14
  • @MichaelDyck Yes, you are right, I updated answer with more generic solution. Only it's better to use `section h1 ~ section` instead of `*`. – dfsq Jul 29 '15 at 08:01
  • No, `section h1 ~ section` doesn't work, because it selects *all* sibling-sections after an h1, not just the first. So in the example, it generates 1.1 for (what should be) 1.2 and 1.3. – Michael Dyck Jul 29 '15 at 20:54
  • Oh, you are actually right, I didn't test it, my bad. – dfsq Jul 29 '15 at 20:58
-2
li{
text-align: center;
}


<ol type="1">
  <li>this</li>
  <li>is</li>
  <li>a</li>
  <li>List</li>
</ol>  

thats not testet but should work

jak89 _1
  • 23
  • 8