htmlcsscss-counter

What is the difference between counter-set and counter-reset in CSS?


I've recently been trying to automatically number headings for my Notion writing. The usual implementation I found on the Internet is like this:

body {
    counter-reset: chapter;
}

h1 {
    counter-reset: subchapter;
}

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

h2::before {
    counter-increment: subchapter;
    content: counter(chapter) "." counter(subchapter) " ";
}

As can be seen, one can use counter-reset to initialize a counter. But when I use this same implementation in Chrome for Notion (via this Chrome extension):

body {
    counter-reset: headings1;
}
div.notranslate[placeholder="Heading 1"] {
    counter-reset: headings2;
}
div.notranslate[placeholder="Heading 2"] {
    counter-reset: headings3;
}

div.notranslate[placeholder="Heading 1"]::before {
  counter-increment: headings1;
  content: "Chapter " counter(headings1) " ";
}
div.notranslate[placeholder="Heading 2"]::before {
  counter-increment: headings2;
  content: "Section " counter(headings2) " ";
}
div.notranslate[placeholder="Heading 3"]::before {
  counter-increment: headings3;
  content: counter(headings2) "." counter(headings3) ".";
}

it just can't work. The result is like this:

Chapter 1 <should be Chapter 1>
    Section 1 <should be Section 1>
        0.1 <Should be 1.1>
        0.1 <Should be 1.2>
        0.1 <Should be 1.3>
    Section 1 <should be Section 2>
        0.1 <should be 2.1>
        0.1 <should be 2.2>
        0.1 <should be 2.3>
Chapter 2 <should be Chapter 2>
    Section 1 <should be Section 1>
        0.1 <Should be 1.1>
        0.1 <Should be 1.2>
        ...

However, if I use counter-set (in a weird manner), everything works again:

body {
    counter-set: headings1 headings2 headings3;
}

div.notranslate[placeholder="Heading 1"] {
    counter-set: headings2;
}

div.notranslate[placeholder="Heading 2"] {
    counter-set: headings3;
}

/*body {*/
/*    counter-reset: headings1;*/
/*}*/
/*div.notranslate[placeholder="Heading 1"] {*/
/*    counter-reset: headings2;*/
/*}*/
/*div.notranslate[placeholder="Heading 2"] {*/
/*    counter-reset: headings3;*/
/*}*/

div.notranslate[placeholder="Heading 1"]::before {
    counter-increment: headings1;
    content: "Chapter " counter(headings1) " ";
}
div.notranslate[placeholder="Heading 2"]::before {
    counter-increment: headings2;
    content: "Section " counter(headings2) " ";
}
div.notranslate[placeholder="Heading 3"]::before {
    counter-increment: headings3;
    content: counter(headings2) "." counter(headings3) ".";
}

Does this mean that one should use counter-set instead of counter-reset to initialize a counter? And what is the difference between counter-set and counter-reset?

I appreciate that this is a weird question and the source of the problem may be a bug or something. But if you know anything about counters in CSS, please share your knowledge:)any kind will help.


Solution

  • In theory, you should create a new counter with counter-set and only use counter-reset if you want to reset an existing counter. Note that counter-reset will create a new counter if there isn’t one already, so, in reality, there’s not much in it under normal circumstances.

    However there is some confusion when you do a counter-reset on a sibling rather than on a parent. I think what’s happening here is that you are creating a new counter with the same name, which is why it isn’t incrementing the way you expected. In this matter Firefox and Chrome appear to have a different interpretation of what should be happening.

    There is some discussion on https://github.com/mdn/browser-compat-data/pull/15666 about the specification.

    The other thing is that Safari doesn’t support counter-set at all. For my purposes I just use counter-reset.