2

I am trying to count elements that is not a regular list.

Easier to explain in code: Fiddle

I have more or less no control over the html.


Instead the DOM look like this:

 <div class="body">
  <div><p class="numlist" >first text</p></div>
  <div><p class="numlist">second text</p></div>
  <div><p class="numlist">third text</p></div>
  <!-- Only here for only here in demonstrative purpose -->
  <div class="should-reset"><p>Start a new counter for the inlines</p></div>
  <div><p class="numlist depth">first text</p></div>
  <div><p class="numlist depth">second text</p></div>
  <div><p class="numlist depth">third text</p></div>
  <!-- Only here for only here in demonstrative purpose -->
  <div class="should-reset"><p>Want to reset the standard counter</p></div>
  <div><p class="numlist reset" >first text</p></div>
  <div><p class="numlist">second text</p></div>
  <div><p class="numlist">third text</p></div>      
</div>

The result I want is something like this:

1. list one
2. list one
3. list one
     1. list two
     2. list two
     3. list two
1. list three
2. list three
3. list three    

But list three always turns out like this like the counter never resets:

1. list three
4. list three
5. list three    
Harry
  • 87,580
  • 25
  • 202
  • 214
Jonathan Andersson
  • 1,342
  • 3
  • 16
  • 31
  • Can you change the classes in the HTML? If you add the `reset` class to the `div` instead of the `p` (like [here](https://jsfiddle.net/yopgm0wr/11/)), it would output what you want. – Harry Feb 17 '17 at 11:57
  • @Harry Nop can not change them. – Jonathan Andersson Feb 17 '17 at 11:58
  • @SebastianBrosch nop not like that, wanted result is written in the question. – Jonathan Andersson Feb 17 '17 at 11:59
  • 2
    @JonathanAndersson: In that case I don't think you can achieve what you are looking for. – Harry Feb 17 '17 at 11:59
  • 1
    @Harry sorry my bad, looked very very similar – dippas Feb 17 '17 at 12:13
  • 1
    @JonathanAndersson: I think your question is similar to [this one](http://stackoverflow.com/questions/41674396/how-do-i-stop-div-tags-interfering-with-counters-multiple-levels-of-headings) actually. Counters, by spec, are supposed to inherit values from the immediately preceding element in the document order. Here, for the second last `.numlist` element's parent, the previous element in document order is the one with `.reset` class and as that element has counter = 1, the second last element should pick this 1 and increment to 2 but for some reason it isn't happening. Expecting it to be a bug. – Harry Feb 17 '17 at 12:15
  • Its ok @dippas. No worries :) – Harry Feb 17 '17 at 12:15

3 Answers3

0

Why don't you simply use <ol>tags?

Remark/addition: This requirement was added to the question after I posted my answer: "I have more or less no control over the html."

.inset {
  margin-left: 20px;
}
<ol>
  <li>
    first text
  </li>
  <li>
    second text
  </li>
  <li>
    third text
  </li>
  </ol>

  <ol class="inset">
    <li>
      first text
    </li>
    <li>
      second text
    </li>
    <li>
      third text
    </li>
  </ol>
  
  <ol>
    <li>
      first text
    </li>
    <li>
      second text
    </li>
    <li>
      third text
    </li>
  </ol>
Johannes
  • 64,305
  • 18
  • 73
  • 130
0

.body {
  counter-reset: standard;  
}

.should-reset {
  counter-reset: standard;
  color: red;
}

.numlist::before {
  counter-increment: standard;
  content: counter(standard) ". ";
}

.numlist.depth::before {
  margin-left: 50px;
}
<div class="body">
  <div><p class="numlist" >first text</p></div>
  <div><p class="numlist">second text</p></div>
  <div><p class="numlist">third text</p></div>
  <div class="should-reset"><p>Start a new counter for the inlines</p> </div>
  <div><p class="numlist depth" depth>first text</p></div>
  <div><p class="numlist depth" depth>second text</p></div>
  <div><p class="numlist depth" depth>third text</p></div>
  <div class="should-reset"><p>Want to reset the standard counter</p> </div>
  <div><p class="numlist" >first text</p></div>
  <div><p class="numlist">second text</p></div>
  <div><p class="numlist">third text</p></div>
</div>

UPD:

.body {
  counter-reset: standard;  
}

.body div:nth-child(3n + 1) {
  counter-reset: standard;
}

.numlist::before {
  counter-increment: standard;
  content: counter(standard) ". ";
}

.numlist.depth::before {
  margin-left: 50px;
}
<div class="body">
  <div><p class="numlist reset" >first text</p></div>
  <div><p class="numlist">second text</p></div>
  <div><p class="numlist">third text</p></div>
  <div><p class="numlist depth" depth>first text</p></div>
  <div><p class="numlist depth" depth>second text</p></div>
  <div><p class="numlist depth" depth>third text</p></div>
  <div><p class="numlist" >first text</p></div>
  <div><p class="numlist">second text</p></div>
  <div><p class="numlist">third text</p></div>
</div>
Mike
  • 1,979
  • 2
  • 16
  • 29
0

Your counter-reset at <div><p class="numlist reset" >first text</p></div> does not reset the original counter because a counter-reset that occurs at an element only applies to the counter defined at the level of that element and its siblings. Instead of resetting the original counter, you are creating a new counter of the same name, a counter whose scope is limited to the P element (and any subsequent siblings or children that exist).

This can be seen by substituting in "counters(standard," AND ") where you wrote counter(standard):

.body {
  counter-reset: standard inline;  
}

div > p.numlist::before {
  counter-increment: standard;
  content: counters(standard," AND ") ". ";
}

div > p.numlist.depth::before {
  counter-increment: inline;
  content: counter(inline) ". ";
  margin-left: 50px;
}

.should-reset {
  color: red;
}

div > p.numlist.reset {
  counter-reset: standard;
}
<div class="body">
  <div>
    <p class="numlist" >first text</p>
  </div>
  <div>
    <p class="numlist">second text</p>
  </div>
  <div>
    <p class="numlist">third text</p>
  </div>
<!-- Only here for only here in demonstrative purpose -->
  <div class="should-reset">
    <p>
      Start a new counter for the inlines
    </p> 
  </div>
  <div>
    <p class="numlist depth" depth>first text</p>
  </div>
  <div>
    <p class="numlist depth" depth>second text</p>
  </div>
  <div>
    <p class="numlist depth" depth>third text</p>
  </div>
  <!-- Only here for only here in demonstrative purpose -->
    <div class="should-reset">
    <p>
    Want to reset the standard counter
    </p> 
  </div>
  <div>
    <p class="numlist reset" >first text</p>
  </div>
  <div>
    <p class="numlist">second text</p>
  </div>
  <div>
    <p class="numlist">third text</p>
  </div>
  
</div>

While, as you see above, the counters() function shows all the current counters of a given name visible from the current scope, not just the most locally defined counter of that name, there is no way for a counter-reset to reach up and reset the instances from higher scopes.

This is not a browser bug (contrary to speculation in a comment beneath the question). From https://drafts.csswg.org/css-lists-3/#nested-counters :

Counters are “self-nesting”; instantiating a new counter on an element which inherited an identically-named counter from its parent creates a new counter of the same name, nested inside the existing counter. This is important for situations like lists in HTML, where lists can be nested inside lists to arbitrary depth: it would be impossible to define uniquely named counters for each level. The counter() function only retrieves the innermost counter of a given name on the element, whereas the counters() function uses all counters of a given name that contain the element.

The scope of a counter therefore starts at the first element in the document that instantiates that counter and includes the element’s descendants and its following siblings with their descendants. However, it does not include any elements in the scope of a counter with the same name created by a counter-reset on a later sibling of the element, allowing such explicit counter instantiations to obscure those earlier siblings.

If you cannot update the HTML, and the <div class="should-reset"> elements are only there for informational purposes, you cannot do this with CSS alone. It would require something like like a :has() pseudo-class, so instead of your

div > p.numlist.reset {
  counter-reset: standard;
}

it would require

div:has(> p.numlist.reset) {
  counter-reset: standard;
}

However, as far as I know, there are no immediate pans by the W3C CSS Working Group to add the :has() pseudo-class to the "live" selector profile, and I doubt that will be done anytime soon, as it could markedly slow performance. (The Selectors Level 4 draft only includes has(): in the "snapshot" profile, suitable for JS methods like querySelector(), and at this time, no major browser even supports it for that, yet.)

Note that even in the case of div:has(> p.numlist.reset) {counter-reset: standard;} (which would only work if :has() is ever adopted in the live profile), one would still be creating a new nested counter named "standard", not resetting the one you created with

.body {
  counter-reset: standard inline;  
}
Jacob C.
  • 345
  • 1
  • 16