Skip to content

[css-conditional-3] Define <declaration> #8795

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
cdoublev opened this issue May 5, 2023 · 8 comments
Open

[css-conditional-3] Define <declaration> #8795

cdoublev opened this issue May 5, 2023 · 8 comments

Comments

@cdoublev
Copy link
Collaborator

cdoublev commented May 5, 2023

<declaration> is only used in the prelude of @supports:

<supports-in-parens> = ( <supports-condition> ) | <supports-feature> | <general-enclosed>
<supports-feature> = <supports-decl>
<supports-decl> = ( <declaration> )

<supports-decl> should evaluate to true if the UA supports the <declaration> in a style rule.

I would like to clarify if unknown-property: var(--custom) or color: invalid-value match <declaration> or <general-enclosed>.

In #8127, I proposed to define <style-feature> (in the prelude of @container) with <declaration> | <ident> but this seemed to be a problem for some people. It was preferred that <general-enclosed> match the above inputs, to avoid storing an invalid declaration.

@cdoublev
Copy link
Collaborator Author

cdoublev commented Apr 2, 2024

I think I didn't understand the following sentence correctly:

If a processor does not implement, with a usable level of support, the value given, then it must not accept the declaration

So color: invalid-value does not match <declaration>. I guess unknown-property: var(--custom) is also invalid. It is a bit unfortunate that:

  • the above sentence does not say explicitly "if a processor does not implement the property and the value given, with a usable level of support"*
  • <declaration> is inconsistent with <declaration-value> and <any-value>, which accept arbitrary values

@cdoublev cdoublev closed this as completed Apr 2, 2024
@svgeesus svgeesus reopened this Apr 2, 2024
@svgeesus
Copy link
Contributor

svgeesus commented Apr 2, 2024

This doesn't seem adequately addressed, to me.

@cdoublev
Copy link
Collaborator Author

cdoublev commented Apr 4, 2024

Right, sorry:

  1. <declaration> still needs to reference a <dfn> somewhere
  2. I was wrong about unknown: 1 or color: invalid not matching <declaration>

I was wrong because browsers accept @import 'sheet.css' supports(unknown: 1); (but do not apply the stylesheet). The difference between accept and support confuses me in:

If a processor does not implement, with a usable level of support, the value given, then it must not accept the declaration or claim support for it.

That said, (unknown: 1) or (color: invalid) matching <general-enclosed> instead of (<declaration>) seems sane to me because they do not need to be re-evaluated, similarly as @media (unknown) {} never needs to be re-evaluated.

This could be achieved by treating the result of matching <supports-decl> (instead of <declaration>) as a syntax error when it fails to be parsed against the grammar, similarly as an unknown media feature name or an invalid value according to the media feature value definition, matches <general-enclosed> (it is evaluated to unknown).

@svgeesus
Copy link
Contributor

@cdoublev do you have spec text suggestions to differentiate "accept" and "support", here?

I just applied your earlier suggested clarification:

both the property and the value given,

svgeesus added a commit that referenced this issue Jul 24, 2024
@cdoublev
Copy link
Collaborator Author

To clarify my previous comment, since it took me a few minutes to remember...

If unknown: 1 or color: invalid were not matching <declaration>, then @import 'sheet.css' supports(unknown: 1) would be invalid, which does not conform to the spec. The grammar is @import ... supports(<declaration>) (simplified).

With @supports (unknown: 1) {}, the grammar is @supports (<declaration> | <any-value>) (also simplified). Parsing unknown: 1 as an invalid <declaration> saves time when evaluating @supports to determine if its contents must be applied by the UA, because it would be probably marked as <any-value> (<general-enclosed>), so they do not neet to re-evaluate its support for the <declaration>.

So I propose to make <supports-decl> invalid when the UA does not support its <declaration>, instead of <declaration>.

I do not like making a grammar sensitive to browser support (which it already is with <declaration>), so it would wise to discuss more about it.

  Style sheets <strong>must not</strong> use such a rule and
  processors <strong>must</strong> ignore such a rule (including all of its contents).
+
+ If the UA does not [=support=] the declaration within the parentheses,
+ <<supports-decl>> is invalid.
  : <<supports-decl>>
  ::
- 	The result is true if the UA [=supports=] the declaration within the parentheses.
+ 	The result is true.
  If a processor does not implement, with a usable level of support,
  both the property and the value given,
  then it <strong>must not</strong>
- accept the declaration or claim support for it.
+ claim support for it.

@cdoublev
Copy link
Collaborator Author

I do not know since which version, but all these rules are now invalid in Chrome, but still valid in FF:

@import "style.css" supports(color: 1);
@import "style.css" supports(color: { var(--custom) });
@import "style.css" supports(--custom: var(1));
@import "style.css" supports(unknown: var(--custom));

@cdoublev
Copy link
Collaborator Author

cdoublev commented Dec 3, 2024

Defining <declaration> with <ident> : <declaration-value> ['!' important]? would make sense to me...

... with a rule in prose making it invalid when <declaration-value> includes a positioned {}-block whereas <ident> does not represent a custom property name, and assuming that <declaration-value> would accept zero or more component values (#11296).

Here are some invalid/valid cases with these restrictions:
Input Valid
--custom: "bad \n string"
--custom: url(bad url)
--custom: ]
--custom: )
--custom: }
--custom: !
color: var(--custom) {}
color: {} var(--custom)
color: ❌ (maybe?)
unknown: var(1) ✔️ (maybe?)
unknown: {} ✔️
--custom: {} positioned {} ✔️
--custom: ✔️

In my opinion, it should not embed more, except maybe for a standard property/descriptor value declared with an omitted value.

supports() should probably take <any-value> as a fallback, so that both supports((invalid)) and supports(invalid) could be consistently valid. Then <declaration> could be alternatively defined as representing any valid declaration in the context...

cdoublev added a commit to cdoublev/css that referenced this issue Dec 16, 2024
This is a significant and long overdue commit that changes the parsing
model for rules and declarations, which are now validated in the
corresponding CSS Syntax algorithms, conforming to a corresponding
change in the specification (w3c/csswg-drafts#8834) a few months ago,
giving up processing all parts of a style sheet with the same parser.

This implementation directly returns a CSSOM representation for rules,
which means that their constructor parses its block contents from the
token stream. The CSSOM entry point "parse a CSS rule" is removed; it is
assumed that CSSOM needs to be vastly updated. <declaration>, which is
parsed with the CSS Syntax algorithm "parse a declaration", now
represents a valid declaration in the context (which is always a style
rule, but this could be configured), which is probably what is expected
but currently unspecified (w3c/csswg-drafts#8795).

Related changes and refactoring will come in future commits.
cdoublev added a commit to cdoublev/css that referenced this issue Dec 16, 2024
This is a significant and long overdue commit that changes the parsing
model for rules and declarations, which are now validated in the
corresponding CSS Syntax algorithms, conforming to a corresponding
change in the specification (w3c/csswg-drafts#8834) a few months ago,
giving up processing all parts of a style sheet with the same parser.

This implementation directly returns a CSSOM representation for rules,
which means that their constructor parses its block contents from the
token stream. The CSSOM entry point "parse a CSS rule" is removed; it is
assumed that CSSOM needs to be vastly updated. <declaration>, which is
parsed with the CSS Syntax algorithm "parse a declaration", now
represents a valid declaration in the context (which is always a style
rule, but this could be configured), which is probably what is expected
but currently unspecified (w3c/csswg-drafts#8795).

Related changes and refactoring will come in future commits.
cdoublev added a commit to cdoublev/css that referenced this issue Dec 16, 2024
This is a significant and long overdue commit that changes the parsing
model for rules and declarations, which are now validated in the
corresponding CSS Syntax algorithms, conforming to a corresponding
change in the specification (w3c/csswg-drafts#8834) a few months ago,
giving up processing all parts of a style sheet with the same parser.

This implementation directly returns a CSSOM representation for rules,
which means that their constructor parses its block contents from the
token stream. The CSSOM entry point "parse a CSS rule" is removed; it is
assumed that CSSOM needs to be vastly updated. <declaration>, which is
parsed with the CSS Syntax algorithm "parse a declaration", now
represents a valid declaration in the context (which is always a style
rule, but this could be configured), which is probably what is expected
but currently unspecified (w3c/csswg-drafts#8795).

Related changes and refactoring will come in future commits.
@cdoublev
Copy link
Collaborator Author

cdoublev commented Feb 17, 2025

Never mind, (color: green;) matches <general-enclosed>.
Another thing I realized today is that Chrome and FF accept `;` in input:
const sheet = new CSSStyleSheet
sheet.insertRule('@supports (color: green;) {}')
sheet.cssRules[0].cssText // @supports (color: green;) {}

It surprised me because CSS Syntax expects color: green; to be parsed with parse a declaration:

"Parse a declaration" is used in @supports conditions.

It invokes consume a declaration but neither consume ;.

I would say that ; is part of a declaration and should be consumed in the corresponding algorithm. <declaration> could then be defined as any input that can be parsed with parse a declaration.

I looked for a corresponding test on WPT but I do not think there is one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants