David Froger
David Froger

Reputation: 665

Numbering h1, h2, h3 with CSS, with presence of article tag

I have this kink of code, where HTML is generated by hieroglyph, and CSS is provided by me:

<html>
<head>
<style>

body {
    counter-reset: chapter 3 section 0;
}

h2 {
    counter-reset: slide 0;
    counter-increment: section;
}
h3 {
    counter-increment: slide;
}


h1:before {
    content: counter(chapter) ". ";
}
h2:before {
    content: counter(chapter) "." counter(section) " ";
}
h3:before {
    content: counter(chapter) "." counter(section) "." counter(slide) " ";
}

</style>
</head>

<body>

<article> <h1>chapter</h1> </article>

<article> <h2>section A</h2> </article>
<article> <h3> slide a</h3> </article>
<article> <h3> slide b</h3> </article>

<article> <h2>section B</h2> </article>
<article> <h3> slide a</h3> </article>
<article> <h3> slide b</h3> </article>

</body>
</html>

I would like to number h1/h2/h3 (which I name chapter, section, slide), but article tag make it difficult.

How can I fix the CSS rules, in order to see:

3. chapter
3.1 section A
3.1.1 side a
3.1.2 side b
3.2 section B
3.2.1 side a
3.2.2 side b

Instead of (h3 are wrongly numbered):

3. chapter
3.1 section A
3.1.1 side a
3.1.1 side b
3.2 section B
3.2.1 side a
3.2.1 side b

Upvotes: 2

Views: 2504

Answers (3)

Claudio Henrique
Claudio Henrique

Reputation: 1

I've been needing this question to validate a list in a pdf, however I had difficulty using it the way it was made available here, since as the h1 was not implemented in the css it does not count. Anyway, there is a solution that I adapted for myself.

<!DOCTYPE html>
<html>
<head>
<style>
body {
  counter-reset: chapter 0 section 0;
}
h1{
    counter-increment: chapter;
}
h2 {
  counter-reset: slide 0;
  counter-increment: section;
}
h3 {
  counter-increment: slide;
}
h1:before {
  content: counter(chapter)". ";
}
h2:before {
  content: counter(chapter)"." counter(section)" ";
}
h3:before {
  content: counter(chapter)"." counter(section)"." counter(slide)" ";
}
</style>
</head>
<body>

<h1>Hello World!</h1>
<p>This paragraph is styled with CSS.</p>
<h2>Test</h2>
<p>CSS comments are not shown in the output.</p>
<h1>Hello World!</h1>
<p>This paragraph is styled with CSS.</p>

</body>
</html>

Upvotes: 0

Harry
Harry

Reputation: 89750

Reasons:

As I had described in my comment to the question, CSS counters are very sensitive to levels and the document structure. If the structure doesn't match a certain pattern then it will affect the entire working of the counters. This is because of how elements inherit the counters and the counter's value. Details about how the counters work, how they are inherited is described in my answer here.

For the sake of more clarity, I have added inline comments in the below snippet to explain the working:

body {
  counter-reset: chapter 3 section 0;
}
h2 {
  counter-reset: slide 0;
  counter-increment: section;
}
h3 {
  counter-increment: slide;
}
h1:before {
  content: counter(chapter)". ";
}
h2:before {
  content: counter(chapter)"." counter(section)" ";
}
h3:before {
  content: counter(chapter)"." counter(section)"." counter(slide)" ";
}
<!-- body creates chapter, section counters -->
<article> <!-- this inherits both counters from its parent and also its value because it is the previous element in document order -->
  <h1>chapter</h1> <!-- inherits both counters and their value from parent -->
</article>

<article> <!-- this inherits both chapter and section counters from parent (body) and the value for the counters from the previous sibling -->
  <h2>section A</h2> <!-- inherits both counters, increments section to 1, creates slide counter. slide counter is visible only to this element but not parent -->
</article>
<article> <!-- this inherits both chapter and section counters from parent (body) and the value for the counters from the previous sibling -->
  <h3> slide a</h3> <!-- inherits chapter, section but sees no slide counter and hence creates a new slide counter and increments to 1, the parent doesn't know about this new slide counter -->
</article>
<article> <!-- this inherits both chapter and section counters from parent (body) and the value for the counters from the previous sibling -->
  <h3> slide b</h3> <!-- inherits chapter, section but sees no slide counter and hence creates a new slide counter and increments to 1, the parent doesn't know about this new slide counter -->
</article>

<article> <!-- this inherits both chapter and section counters from parent (body) and the value for the counters from the previous sibling -->
  <h2>section B</h2>  <!-- inherits both counters, increments section to 2, creates slide counter. slide counter is visible only to this element but not parent -->
</article>
<article> <!-- this inherits both chapter and section counters from parent (body) and the value for the counters from the previous sibling -->
  <h3> slide a</h3> <!-- inherits chapter, section but sees no slide counter and hence creates a new slide counter and increments to 1, the parent doesn't know about this new slide counter --> 
</article>
<article> <!-- this inherits both chapter and section counters from parent (body) and the value for the counters from the previous sibling -->
  <h3> slide b</h3> <!-- inherits chapter, section but sees no slide counter and hence creates a new slide counter and increments to 1, the parent doesn't know about this new slide counter --> 
</article>

However the solution described in the linked thread would still not work for this case because of how the document is structured. Even if we reset the slide counter at body and make the counter visible to all child elements, the reset to 0 happens only when a h2 is encountered. Since all h2 are inside their respective article and the article (and thereby the child h2) already have slide counter inherited from their parent, another reset at a different level possibly results in self nesting (that is, new slide counter being created nested under the parent slide). Because of it, subsequent reset have no effect and the h3 elements keep continuing the numbering as seen in the below snippet:

body {
  counter-reset: chapter 3 section 0 slide 0;
}
h2 {
  counter-reset: slide 0;
  counter-increment: section;
}
h3 {
  counter-increment: slide;
}
h1:before {
  content: counter(chapter)". ";
}
h2:before {
  content: counter(chapter)"." counter(section)" ";
}
h3:before {
  content: counter(chapter)"." counter(section)"." counter(slide)" ";
}
<article>
  <h1>chapter</h1>
</article>
<article>
  <h2>section A</h2>
</article>
<article>
  <h3> slide a</h3>
</article>
<article>
  <h3> slide b</h3>
</article>
<article>
  <h2>section B</h2>
</article>
<article>
  <h3> slide a</h3>
</article>
<article>
  <h3> slide b</h3>
</article>


Solution:

There are three solutions to this situation and they are as follows:

  1. Change the document structure to have the h3 elements grouped under the same article like in the below snippet.

    body {
      counter-reset: chapter 3 section 0;
    }
    h2 {
      counter-reset: slide 0;
      counter-increment: section;
    }
    h3 {
      counter-increment: slide;
    }
    h1:before {
      content: counter(chapter)". ";
    }
    h2:before {
      content: counter(chapter)"." counter(section)" ";
    }
    h3:before {
      content: counter(chapter)"." counter(section)"." counter(slide)" ";
    }
    <article>
      <h1>chapter</h1>
    </article>
    <article>
      <h2>section A</h2> <!-- The reset here has no effect because it creates a different instance -->
    </article>
    <article>
      <h3> slide a</h3> <!-- Parent doesn't have slide counter, so this creates one and increments it to 1 -->
      <h3> slide b</h3> <!-- This inherits slide counter's value fom previous element and increments to 2 -->
    </article>
    <article>
      <h2>section A</h2> <!-- The reset here has no effect because it creates a different instance -->
    </article>
    <article>
      <h3> slide a</h3> <!-- Parent doesn't have slide counter, so this creates one and increments it to 1 -->
      <h3> slide b</h3> <!-- This inherits slide counter's value fom previous element and increments to 2 -->
    </article>

  2. Give each article a class which indicates what it contains and then do the counter-reset or counter-increment at the parent level itself. This means the counters and their values would be visible to all siblings. This in my opinion is the best approach without modifying your structure.

    .h1-container {
      counter-reset: chapter 3 section 0 slide 0;
    }
    .h2-container {
      counter-reset: slide 0;
      counter-increment: section;
    }
    .h3-container {
      counter-increment: slide;
    }
    h1:before {
      content: counter(chapter)". ";
    }
    h2:before {
      content: counter(chapter)"." counter(section)" ";
    }
    h3:before {
      content: counter(chapter)"." counter(section)"." counter(slide)" ";
    }
    <article class='h1-container'>
      <h1>chapter</h1>
    </article>
    <article class='h2-container'>
      <h2>section A</h2>
    </article>
    <article class='h3-container'>
      <h3> slide a</h3>
    </article>
    <article class='h3-container'>
      <h3> slide b</h3>
    </article>
    <article class='h2-container'>
      <h2>section A</h2>
    </article>
    <article class='h3-container'>
      <h3> slide a</h3>
    </article>
    <article class='h3-container'>
      <h3> slide b</h3>
    </article>

  3. Use JavaScript or jQuery (or other preferred libraries) to count the elements and set numbering according to it.

Upvotes: 1

Mr Lister
Mr Lister

Reputation: 46579

How about this. No JavaScript; HTML markup the same as you had originally.

body {
  counter-reset: chapter 3 section 0 slide 2;
}

h2 {
  counter-increment: slide -2 section;
}

h3 {
  counter-increment: slide;
}

h1:before {
  content: counter(chapter)". ";
}

h2:before {
  content: counter(chapter)"." counter(section)" ";
}

h3:before {
  content: counter(chapter)"." counter(section)"." counter(slide)" ";
}
<article> <h1>chapter</h1> </article>

<article> <h2>section A</h2> </article>
<article> <h3> slide a</h3> </article>
<article> <h3> slide b</h3> </article>

<article> <h2>section B</h2> </article>
<article> <h3> slide a</h3> </article>
<article> <h3> slide b</h3> </article>

It works by not doing a counter-reset, but a counter-increment for the slide counter, thus keeping the counter global. However, there's a catch: it works only when the number of slides is fixed (in this case, 2).

Upvotes: 0

Related Questions