Z.H.
Z.H.

Reputation: 259

Wrong numbering with css counters

Why the following css doesn't get correct numbering of sections (http://jsfiddle.net/75MHS/)? When I put h3 and h4 inside divs, all chapter numbers and section numbers are always one. But when I remove div containers, the numbers are all correct.

<!DOCTYPE html>
<html>
<head>
<style type='text/css'>
h3 {
  counter-increment: chapter;
  counter-reset: section;
}
h3:before {
  content: "Chapter " counter(chapter) " ";
}
h4 {
  counter-increment: section;
}
h4:before {
  content: counter(section) " ";
}
</style>
</head>
<body>
<!-- wrong counter -->
<div><h3>dddd</h3></div>
<div><h4>dddd</h4></div>
<div><h4>dddd</h4></div>
<div><h3>dddd</h3></div>
<div><h4>dddd</h4></div>
<div><h4>dddd</h4></div>

<!-- correct counter -->
<!--
<h3>dddd</h3>
<h4>dddd</h4>
<h4>dddd</h4>
<h3>dddd</h3>
<h4>dddd</h4>
<h4>dddd</h4>
-->
</body>
</html>

Upvotes: 6

Views: 1901

Answers (4)

myajouri
myajouri

Reputation: 3124

The reason it works as intended in the second section (without the div's) but doesn't in the fist section is due to counter scope. According to the W3C:

The scope of a counter starts at the first element in the document that has a 'counter-reset' for that counter and includes the element's descendants and its following siblings with their descendants.

In the second half of the html, the h3s and h4s are siblings, therefore, the counter-reset defined on the h3 applies to the following h4 siblings. In the first part of the html, the h4s are not descendants nor siblings of the h3s, therefore, the counter-rest has no effect on them since they're out of scope.

The other thing is, if counter-reset is not defined in a given scope, it assumes a value of 0 each time you counter-increment or refer to the counter in a content rule, which explains why you're getting all 1s in the first part of the html:

If 'counter-increment' or 'content' on an element or pseudo-element refers to a counter that is not in the scope of any 'counter-reset', implementations should behave as though a 'counter-reset' had reset the counter to 0 on that element or pseudo-element.


If you have to wrap things in divs, I would:

  1. Define a counter-reset for the chapters counter on body, so that it's not assumed 0 each time you use a counter-increment.

  2. Either nest the h4s under their parent h3s (which is not cool) or make them siblings to ensure they're in the right scope.


New HTML:

<div>
    <h3>dddd</h3>
    <h4>dddd</h4>
    <h4>dddd</h4>
</div>
<div>
    <h3>dddd</h3>
    <h4>dddd</h4>
    <h4>dddd</h4>
</div>

Addition to CSS:

body {
    counter-reset: chapter;
}

http://jsfiddle.net/myajouri/QpG9d/

Upvotes: 4

Jukka K. Korpela
Jukka K. Korpela

Reputation: 201886

The reason is that “Counters are ‘self-nesting’, in the sense that resetting a counter in a descendant element or pseudo-element automatically creates a new instance of the counter.” (CSS 2.1, 12.4.1 Nested counters and scope).

So in the “wrong counter” case, each div element containing an h3 element has its own counter named chapter, and each h3 increments such a local counter.

If you need div elements (or section elements) for grouping, you can use them this way:

<div class=chapter>
<h3>dddd</h3>
<h4>dddd</h4>
<h4>dddd</h4>
</div>
<div class=chapter>
<h3>dddd</h3>
<h4>dddd</h4>
<h4>dddd</h4>
</div>

And with such a structure, your CSS would have .chapter instead of h3:

.chapter {
  counter-increment: chapter;
  counter-reset: section;
}

Upvotes: -1

Surjith S M
Surjith S M

Reputation: 6740

I have added class to the wrap to differentiate div.

Working Demo

HTML

<div class="head"><h3>dddd</h3></div>
<div class="sub"><h4>dddd</h4></div>
<div class="sub"><h4>dddd</h4></div>
<div class="head"><h3>dddd</h3></div>
<div class="sub"><h4>dddd</h4></div>
<div class="sub"><h4>dddd</h4></div>

CSS

div.head {
  counter-increment: chapter;
  counter-reset: section;
}

div.head h3:before {
  content: "Chapter " counter(chapter) " ";
}

div.sub {
  counter-increment: section;
}

div.sub h4:before {
  content: counter(section) " ";
}

Upvotes: 1

Adonis K. Kakoulidis
Adonis K. Kakoulidis

Reputation: 5132

You are forgetting that the divs are part of the DOM tree now, you either target them as well or you remove them.

div {
    counter-increment: chapter;
    counter-reset: section;
}
div:before {
    content: "Chapter " counter(chapter) " ";
}

Upvotes: 1

Related Questions