Search code examples
htmlcsscss-counter

counter-increment on parent, but content on child


I am strugling a little bit with the css 'counter-increment' and 'counter-reset' properties. I got it working perfectly with lists already, but when it comes to header tags for example, things get a little less clear for me.

Imagine the following layout:

<div id="root">
    <div class="section">
        <h1 class="header">Header</h1>
        
        <div class="section">
            <h2 class="header">Header</h2>
            <!-- can be nested multiple times -->
        </div>
    </div>
    <div class="section">
        <h1 class="header">Header</h1>
        <!-- content -->
    </div>
</div>

I would like the header tags to be numbered (including nested counting!) but since the header tags themselves don't embed, but their parents I can't get it working properly. So this is what I got so far (based on logic, but not closest solution towards what I want to achieve! I tried every possible combination I could think of)

#root
{
    /* root should reset counter */
    counter-reset: section_header;
}

#root .section
{
    /* since every section has a header tag, we should count sections-divs, as they wrap children as well */
    counter-increment: section_header;
}

.section .header::before
{
    /* This would take care of the display, but I suspect it doesn't obtain the correct value since the scope of the counter is not available? */
    content: counters(section_header, ".") " ";
}

I would appreciate any direction towards a solution (if one exist).

ps. I should mention I mainly test this on Chrome, but I found this one on other browsers as well.

Edit

The format I am looking for is '1.1', '1.2', '1.2.1' etc.. Every nested section should append another counter layer, although I can get this to work without layering (single depth), the dynamic multi-layering is kind of tricky to achieve apperently.


Solution

  • Update: I saw the MDN example that you probably used for inspiration in creating this. The confusing part of translating that into your markup is that they use <ol> and <li> tags which encompass child elements. This doesn't make as much sense in the context of header <h_> elements, but it seems you have to keep the child elements within them to accomplish the same thing. I added the after elements and some light css to show where each element ends. Hope this helps.

    .section {
      counter-reset: section;                /* Creates a new instance of the
                                                section counter with each ol
                                                element */
      list-style-type: none;
    }
    
    .header::before {
      counter-increment: section;            /* Increments only this instance
                                                of the section counter */
      content: counters(section, ".") " ";   /* Combines the values of all instances
                                                of the section counter, separated
                                                by a period */
    }
    
    .section{
      font-size: 16px;
      margin: 10px 0;
    }
    h1::after {
      content: ' (end h1)';
    }
    
    h2 {
      margin-left: 10px;
    }
    h2::after {
      content: ' (end h2)';
    }
    
    h3 {
      margin-left: 20px;
    }
    h3::after {
      content: ' (end h3)';
    }
    <div id="root">
      <div class="section">
        <h1 class="header">item</h1>          <!-- 1     -->
        <h1 class="header">item               <!-- 2     -->
          <div class="section">
            <h2 class="header">item</h2>      <!-- 2.1   -->
            <h2 class="header">item</h2>      <!-- 2.2   -->
            <h2 class="header">item           <!-- 2.3   -->
              <div class="section">
                <h3 class="header">item</h3>  <!-- 2.3.1 -->
                <h3 class="header">item</h3>  <!-- 2.3.2 -->
              </div>
             </h2>
             <h2 class="header">item 
              <div class="section">
                <h3 class="header">item</h3>  <!-- 2.4.1 -->
                <h3 class="header">item</h3>  <!-- 2.4.2 -->
                <h3 class="header">item</h3>  <!-- 2.4.3 -->
              </div>
            </h2>
            <h2 class="header">item</h2>      <!-- 2.5   -->
          </div>
        </h1>
        <h1 class="header">item</h1>          <!-- 3     -->
        <h1 class="header">item</h1>          <!-- 4     -->
      </div>
    </div>