Skip to content

Commit

Permalink
fix(css): clarify counter-set vs counter-reset (#35258)
Browse files Browse the repository at this point in the history
* fix(css): clarify counter-set vs counter-reset

* Apply suggestions from code review

Co-authored-by: Brian Thomas Smith <[email protected]>

* add inheritance section

---------

Co-authored-by: Brian Thomas Smith <[email protected]>
  • Loading branch information
OnkarRuikar and bsmth authored Aug 29, 2024
1 parent e8fe043 commit cdc0015
Show file tree
Hide file tree
Showing 3 changed files with 213 additions and 9 deletions.
48 changes: 45 additions & 3 deletions files/en-us/web/css/counter-reset/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ counter-reset: unset;
The `counter-reset` property accepts a list of one or more space-separated counter names or the keyword `none`. For counter names, regular counters use the format `<counter-name>`, and reversed counters use `reversed(<counter-name>)`, where `<counter-name>` is a {{cssxref("custom-ident", "&lt;custom-ident&gt;")}} or `list-item` for the built-in {{HTMLElement("ol")}} counter. Optionally, each counter name can be followed by an `<integer>` to set its initial value.

- {{cssxref("custom-ident", "&lt;custom-ident&gt;")}}
- : Specifies the counter name to create and initialize using the {{cssxref("custom-ident", "&lt;custom-ident&gt;")}} format.
- : Specifies the counter name to create and initialize using the {{cssxref("custom-ident", "&lt;custom-ident&gt;")}} format. The `reversed()` functional notation can be used to mark the counter reversed.
- {{cssxref("&lt;integer&gt;")}}
- : The value to reset the counter to on each occurrence of the element.
- : The initial value to set on the newly created counter.
Defaults to `0` if not specified.
- `none`
- : Specifies that no counter initialization should occur.
Expand All @@ -57,7 +57,8 @@ The `counter-reset` property accepts a list of one or more space-separated count

The `counter-reset` property can create both regular and, in browsers that support it, reversed counters. You can create multiple regular and reversed counters, each separated by a space. Counters can be a standalone name or a space-separated name-value pair.

After creating a counter using `counter-reset`, you can adjust its value by using the {{cssxref("counter-set")}} property. This is counterintuitive because, despite its name, the `counter-reset` property is used for creating and initializing counters, while the `counter-set` property is used for resetting the value of an existing counter.
> [!WARNING]
> There is [a difference between `counter-reset` and `counter-set` properties](/en-US/docs/Web/CSS/CSS_counter_styles/Using_CSS_counters#difference_between_counter-set_and_counter-reset). After creating a counter using `counter-reset`, you can adjust its value by using the {{cssxref("counter-set")}} property. This is counterintuitive because, despite its name, the `counter-reset` property is used for creating and initializing counters, while the `counter-set` property is used for resetting the value of an existing counter.

Setting `counter-increment: none` on a selector with greater specificity overrides the creation of the named counter set on selectors with lower specificity.

Expand Down Expand Up @@ -134,6 +135,47 @@ ol {

Using `counter-reset`, we set the implicit `list-item` counter to start counting at `3` for every `ol`. Then, the first item would be numbered 4, second would be numbered 5, etc., similar to the effect of writing [`<ol start="4">`](/en-US/docs/Web/HTML/Element/ol#start) in HTML.

### Using a reverse counter

In the following example, we've declared a reversed counter named 'priority'. The counter is being used to number five tasks.

```html
<ul class="stack">
<li>Task A</li>
<li>Task B</li>
<li>Task C</li>
<li>Task D</li>
<li>Task E</li>
</ul>
```

```css hidden
@supports not (counter-reset: reversed(priority)) {
.stack {
display: none;
}
body::after {
content: "Your browser doesn't support the reversed counters yet.";
}
}
```

```css
li::before {
content: counter(priority) ". ";
counter-increment: priority -1;
}

.stack {
counter-reset: reversed(priority);
list-style: none;
}
```

{{EmbedLiveSample("Using a reverse counter", 140, 150)}}

In the output, the items are numbered in reversed order from 5 to 1. Notice in the code we haven't specified the counter's initial value. The browser automatically calculates the initial value at layout-time using the counter increment value.

## Specifications

{{Specifications}}
Expand Down
6 changes: 4 additions & 2 deletions files/en-us/web/css/counter-set/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ browser-compat: css.properties.counter-set

{{CSSRef}}

The **`counter-set`** [CSS](/en-US/docs/Web/CSS) property sets [CSS counters](/en-US/docs/Web/CSS/CSS_counter_styles/Using_CSS_counters) to the given values.
The **`counter-set`** [CSS](/en-US/docs/Web/CSS) property sets [CSS counters](/en-US/docs/Web/CSS/CSS_counter_styles/Using_CSS_counters) on the element to the given values.

The `counter-set` property will create a new counter for each named counter in the list of space-separated counter and value pairs that doesn't already exist. If a named counter in the list is missing a value, the value of the counter will be set to `0`.
If the counters don't exist the `counter-set` property creates a new counter for each named counter in the list of space-separated counter and value pairs. However, to create a new counter it is recommended to use the {{cssxref("counter-reset")}} CSS property.

If a named counter in the list is missing a value, the value of the counter will be set to `0`.

{{EmbedInteractiveExample("pages/css/counter-set.html")}}

Expand Down
168 changes: 164 additions & 4 deletions files/en-us/web/css/css_counter_styles/using_css_counters/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,21 @@ spec-urls: https://drafts.csswg.org/css-lists/#auto-numbering
{{CSSRef}}

**CSS counters** let you adjust the appearance of content based on its location in a document.
For example, you can use counters to automatically number the headings in a webpage, or to change the numbering on ordered lists.
For example, you can use counters to automatically number the headings on a webpage or to change the numbering on ordered lists.

Counters are, in essence, variables maintained by CSS whose values may be incremented or decremented by CSS rules that track how many times they're used. The following things affect the counter values on an element:

1. Counters are [inherited](#counter_inheritance_and_propagation) from the parent element or received from a previous sibling.
2. New counters are instantiated using {{cssxref("counter-reset")}} property.
3. Counters are incremented using {{cssxref("counter-increment")}} property.
4. Counters are directly set to a value using the {{cssxref("counter-set")}} property.

Counters are, in essence, variables maintained by CSS whose values may be incremented or decremented by CSS rules that track how many times they're used.
You can define your own named counters, and you can also manipulate the `list-item` counter that is created by default for all ordered lists.

## Using counters

To use a counter it must first be initialized to a value with the {{cssxref("counter-reset")}} property.
The counter's value can then be increased or decreased using {{cssxref("counter-increment")}} property.
The counter's value can be increased or decreased using the {{cssxref("counter-increment")}} property and can be directly set to a specific value using the {{cssxref("counter-set")}} property.
The current value of a counter is displayed using the {{cssxref("counter", "counter()")}} or {{cssxref("counters", "counters()")}} function, typically within a [pseudo-element](/en-US/docs/Web/CSS/Pseudo-elements) {{CSSxRef("content")}} property.

Counters can only be set, reset, or incremented in elements that generate boxes.
Expand Down Expand Up @@ -51,7 +57,15 @@ h3::before {
}
```

You can specify the value to increment or decrement the counter after the counter name, using a positive or negative number.
You can specify the increment or decrement amount after the counter name. It can be a positive or negative number, but defaults to `1` if no integer is provided.

Apart from increment or decrement, counters can also be explicitly set to a value using {{cssxref("counter-increment")}} property.

```css
.done::before {
counter-set: section 20;
}
```

The counter's name must not be `none`, `inherit`, or `initial`; otherwise the declaration is ignored.

Expand Down Expand Up @@ -129,6 +143,152 @@ The counter value is decreased by specifying a negative value for {{cssxref("cou
> You can also use {{cssxref("counter-increment")}} to decrement a non-reversed counter.
> The main benefit of using a reversed counter is the default initial value, and that the `list-item` counter automatically decrements reversed counters.
### Counter inheritance and propagation

Each element or pseudo-element has a set of counters in the scope of that element. Initial counters in the set are received from the element's parent and the preceding sibling. The counter values are received from the last descendent of the previous sibling, the last sibling, or the parent.

When an element declares a counter, the counter is nested inside the counter with the same name received from the parent. If the parent doesn't have a counter with the same name then the counter is added to the element's counters set as it is. A counter with the same name received from the previous sibling is removed from the counters set.

The {{cssxref("counter", "counter()")}} function retrieves the innermost counter with the provided name. And the {{cssxref("counters", "counters()")}} function retrieves the entire counter tree with the given name.

In the following example, we are demoing an inherited counter named `primary` and a sibling counter named `secondary`. All the `<div>` elements display their counters using the `counters()` function. Note that all the counters have been created using `counter-reset` property, and none of the counters have been incremented.

```html
<section>
counter-reset: primary 3
<div>A</div>
<div>B</div>
<div>C</div>
<div class="same-primary-name">D</div>
<span> counter-reset: primary 6</span>
<div>E</div>
<div class="new-secondary-name">F</div>
<span> counter-reset: secondary 5</span>
<div>G</div>
<div>H</div>
<div class="same-secondary-name">I&nbsp;</div>
<span> counter-reset: secondary 10</span>
<div>J&nbsp;</div>
<div>K</div>
<section></section>
</section>
```

```css hidden
.same-primary-name,
.new-secondary-name,
.same-secondary-name {
display: inline-block;
}

@counter-style style {
system: numeric;
symbols: "" "1" "2" "3" "4" "5" "6" "7" "8" "9" "10";
}
```

```css
/* create 'primary' counter on divs' parent */
section {
counter-reset: primary 3;
}

div::after {
content: " ('primary' counters: " counters(primary, "-", style)
", 'secondary' counters: " counters(secondary, "-", style) ")";
color: blue;
}

/* create new 'primary' counter */
.same-primary-name {
counter-reset: primary 6;
}

/* create 'secondary' counter on div 'F' */
.new-secondary-name {
counter-reset: secondary 5;
}

/* override the sibling 'secondary' counter */
.same-secondary-name {
counter-reset: secondary 10;
}
```

{{EmbedLiveSample("Counter inheritance and propagation", "100%", 250)}}

The section element initializes a counter named `primary` with value `3`, and all the child `<div>`s receive the inherited `primary` counter. The element 'D' creates a new `primary`(value `6`) counter which gets nested in the counter received from the parent, so the element has two counters named `primary` with values `3` and `6`.

The element 'F' creates the `secondary`(value `5`) counter for the first time, and it passes the counter to the next sibling 'G'. The element 'G' passes the counter to the next element 'H' and so on. Next, the element 'I' creates a new counter with the same name `secondary`(value `10`), but it drops the `secondary`(value `5`) counter received from the previous sibling 'H' and passes its own counter to 'J'.

### Difference between counter-set and counter-reset

The {{cssxref("counter-set")}} property updates an existing counter and if no counter with the name exists then a new counter is instantiated. The {{cssxref("counter-reset")}} property _always_ creates a new counter.

In the following example, we have two sub-lists inside a parent list. Each list item has been numbered using a counter named 'item'. The first sub-list uses {{cssxref("counter-set")}} property and the second sub-list uses {{cssxref("counter-reset")}} property to change the 'item' counter.

```html
<ul class="parent">
<li>A</li>
<li>B</li>
<li>
C (the counter updated using `counter-set`)
<ul class="sub-list-one">
<li>sub-A</li>
<li>sub-B</li>
</ul>
</li>
<li>D</li>
<li>
E (a new counter created using `counter-reset`)
<ul class="sub-list-two">
<li>sub-A</li>
<li>sub-B</li>
<li>sub-C</li>
</ul>
</li>
<li>F</li>
<li>G</li>
</ul>
```

```css hidden
ul {
list-style: none;
}
```

```css
/* create a new counter for the first time */
.parent {
counter-reset: item 0;
}

/* increment the counter on each list item */
li {
counter-increment: item;
}

/* show numbers on list items */
li::before {
content: counter(item) " ";
}

/* change the existing counter value */
.sub-list-one {
counter-set: item 10;
}

/* change the counter value */
.sub-list-two {
counter-reset: item 0;
}
```

{{EmbedLiveSample("Difference between counter-set and counter-reset", "100%", 300)}}

Notice how the first sub-list items start receiving numbers from `11`, and the numbering is continued in the parent list. This is because the `counter-set` property updates the same 'item' counter declared on the `.parent` element. Then notice how the second sub-list items receive new numbering starting from '1' and the parent list items after it don't carry forward the numbering. This is because the `counter-reset` property created a new counter with the same name so the parent list items kept using the old counter.

### List item counters

Ordered lists, as created using {{HTMLElement("ol")}} elements, implicitly have a counter named `list-item`.
Expand Down

0 comments on commit cdc0015

Please sign in to comment.