Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,100 @@ If you enter `unset` or `gibberish`, the JavaScript updates the `style` on the {
> [!NOTE]
> When declaring custom properties, consider using `@property` with the {{cssxref("@property/syntax","syntax")}} descriptor so the browser can properly compare computed values.

### Plain versus range syntax in style queries
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is all great. I'd argue a little of it should go in the reference, but even if it did it should all stay here too.


When a `<style-feature>` includes a value, you can express the comparison in two different ways. They look similar but behave very differently, and choosing the right one matters.

The **plain syntax** uses a colon, the same syntax used in a CSS declaration:

```css
@container style(--n: 3) {
/* … */
}
```

This form is true if the [computed value](/en-US/docs/Web/CSS/Guides/Cascade/Property_value_processing#computed_value) of the property matches the value on the right. For an [unregistered](#unregistered_custom_properties) custom property, the computed value is the property's value as written: the browser doesn't evaluate `calc()` or other expressions inside it. The match is essentially a comparison of the two values' tokens. To match equivalent values (such as `blue` and `#0000ff`), [register the custom property](#registered_properties) with `@property` and a `syntax` descriptor.

The **range syntax** uses a comparison operator (`=`, `<`, `<=`, `>`, or `>=`):

```css
@container style(--n = 3) {
/* … */
}
```

To evaluate this form, the browser:

1. Resolves each side (custom property names are looked up as if used with [`var()`](/en-US/docs/Web/CSS/Reference/Values/var)).
2. Parses each side as one of {{cssxref("&lt;number&gt;")}}, {{cssxref("&lt;percentage&gt;")}}, {{cssxref("&lt;length&gt;")}}, {{cssxref("&lt;angle&gt;")}}, {{cssxref("&lt;time&gt;")}}, {{cssxref("&lt;frequency&gt;")}}, or {{cssxref("&lt;resolution&gt;")}}. If either side can't be parsed as one of those types, the query is false.
3. If both sides have the same type, computes each side (evaluating any `calc()` expressions) and performs the numeric comparison. Otherwise, the query is false.

Consider the following example, where `--n` is set to a `calc()` expression:

```css
.box {
--n: calc(6/2);
}

/* Evaluates to FALSE: */
/* the computed value of --n is the string `calc(6/2)`, which is */
/* not equal to the string `3`. */
@container style(--n: 3) {
/* … */
}

/* Evaluates to TRUE: */
/* both sides are parsed as <integer>, calc(6/2) is computed to 3, */
/* and 3 = 3. */
@container style(--n = 3) {
/* … */
}
```

The range syntax also supports a three-value form for testing whether a value falls within an interval. Both comparators must point the same way:

```css
@container style(0 < --n < 10) {
/* true when --n is greater than 0 and less than 10 */
}

@container style(100px > --width > 50px) {
/* true when --width is less than 100px and greater than 50px */
}
```

The range syntax is also more flexible in how each side is written. Either side can be a custom property name, a [`var()`](/en-US/docs/Web/CSS/Reference/Values/var) reference, a literal value, or a `calc()` expression, and the operands can appear in any order. The following are all valid:

```css
@container style(3 = --n) {
/* … */
}
@container style(var(--n) = 3) {
/* … */
}
@container style(calc(6/2) = var(--n)) {
/* … */
}
```

The plain syntax is more restrictive: the left-hand side must be the custom property name (without `var()`), and the value goes on the right. The following are all **invalid**:

```css example-bad
@container style(var(--n): 3) {
/* … */
}
@container style(3: --n) {
/* … */
}
```

Because the range syntax requires both sides to parse as one of the listed numeric types, it can't be used to compare keyword-like values. For example, given `--s: new`, the query `style(--s = new)` is false (because `new` isn't a number, length, etc.), while `style(--s: new)` is true.

In short:

- Use **`style(--variable: value)`** for keyword-like or string-like matching, such as `style(--stock: low)` or `style(--theme: dark)`.
- Use **`style(--variable = value)`** (or `<`, `<=`, `>`, `>=`) for numeric comparisons, such as `style(--columns >= 3)` or `style(--gap = 1rem)`.

### Nested queries

Container queries can be nested within other container queries. The styles defined inside multiple nested container queries are applied when all of the wrapping container queries are true.
Expand Down
9 changes: 9 additions & 0 deletions files/en-us/web/css/reference/at-rules/@container/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,15 @@ Note that [`!important`](/en-US/docs/Web/CSS/Reference/Values/important) is allo

The global `revert` and `revert-layer` are invalid as values in a `<style-feature>` and cause the container style query to be false.

#### Plain (`:`) versus range (`=`) syntax
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider doing all as below. I see the point of comparing the two you have because they look similar and I guess doing = will be a gotcha. But in most cases you'll likely us this as an actual range - so > is far more likely.

Suggested change
#### Plain (`:`) versus range (`=`) syntax
#### Plain (`:`) versus range (`=`,`<`, `<=`, `>`, `>=`) syntax

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, having read the guide now, I'd be tempted to call this range syntax, make it mostly about range syntax, and expand it out with some of the information in the guide.
This focuses currently on the comparision of the forms - but I see this as the reference which needs to mostly talk about what range syntax is, not how it compares.

Specifically

  1. The material in "To evaluate this form, the "
  2. The point that there is a syntax with three values. MORE important, make it clear that they don't evaluate in a daisy chain, which I just assumed.
  3. I'd keep the comparsion as a gotcha example. It is useful.

Thoughts?


When a `<style-feature>` includes a value, you can write the comparison in two forms that look similar but behave differently:

- `style(--n: 3)` (plain) matches the property's _computed value_ against the right-hand side. For an unregistered custom property, the computed value is the value as authored, so `style(--n: 3)` is false when `--n` is `calc(6/2)`. Use this form for keyword-like values, such as `style(--stock: low)`.
- `style(--n = 3)` (range) parses both sides as a number, length, percentage, etc., and compares numerically. With the same `--n: calc(6/2)`, `style(--n = 3)` is true. The range syntax also supports `<`, `<=`, `>`, `>=`, three-value intervals such as `style(0 < --n < 10)`, and flexible operand ordering.

For the full rules and more examples, see [Plain versus range syntax in style queries](/en-US/docs/Web/CSS/Guides/Containment/Container_size_and_style_queries#plain_versus_range_syntax_in_style_queries) in the container style queries guide.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pepelsbey @dletorey Can you guys co-ordinate. I just reviewed a section on this topic in #44003

  1. FYI, the problem I raised with that PR is that this section is in "examples" but the content of all these examples is actually guide. Arguably all of this should be in a description. Possibly to much restructure for now.

  2. That PR didn't include a proper guide. This is better, but you might want to take the example from the other PR into this.

  3. The range syntax isn't a CSS declaration as I undersand it, from the sentence in previous section "The parameter of each style() is a single <style-feature>. A <style-feature> is a valid CSS declaration, a CSS property, or a <custom-property-name>.".

    • Whatever it is, we should forward reference earlier and link down here - i.e. make it clear earlier that there are effectively "boolean" comparision on computed values and range comparsion on numerical values.
  4. The range syntax has implications also in that it compares numbers, so presumably if you compare a property like color: red to a range it might be meaningless - I'm not sure how that would coerce either.

    Minimally it is worth noting here what the intent is - i.e. why it was added and where you can/cannot use it.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PS See my comments on th intro https://github.com/mdn/content/pull/44014/changes#r3206101519

Most of this is still valid. If you make it more about the range and less about the comparion of forms this should just work.

### Scroll-state queries

See [Using container scroll-state queries](/en-US/docs/Web/CSS/Guides/Conditional_rules/Container_scroll-state_queries) for scroll-state query examples.
Expand Down
Loading