Skip to content
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

[css-values] Other options for value-agnostic delimiters #6705

Open
nex3 opened this issue Oct 1, 2021 · 14 comments
Open

[css-values] Other options for value-agnostic delimiters #6705

nex3 opened this issue Oct 1, 2021 · 14 comments

Comments

@nex3
Copy link
Contributor

nex3 commented Oct 1, 2021

In #581, a semicolon has been proposed as a delimiter in the function mix( <percentage> ; <start-value> ; <end-value>). Commas can't be naïvely used as delimiters here because <start-value> and <end-value> need to be able to be any valid property value, some of which may include commas of their own. But as @LeaVerou points out in #581 (comment), introducing a semicolon as a valid character in a value context is likely to break existing tooling fairly severely. Tools will eventually update to support it—in Sass for example we could probably make it work by adding semicolon as a new form of list delimiter—but until that update happens and is widely adopted by all users of these tools, it's likely that this syntax will render the mix() function painful or impossible to use by many people.

Given that, I thought I'd toss out an alternative idea for how to structure this syntax in a way that's easier for existing tools to parse (and possibly also more similar to existing CSS functions), while also allowing arbitrary property values. I'm not particularly married to any particular configuration of this solution, but I'd like to avoid the semicolon if possible and I'm hoping this can at least inspire some useful discussion of how that might be accomplished.

My core idea would be to wrap the <start-value> and <end-value> productions in some other syntax to make the scope of the values unambiguous, similarly to how calc() wraps an unusual syntactic context. This could look more explicit like mix( <percentage> , value( <start-value> ) , value( <end-value> ) ) or more terse like mix( <percentage> , [ <start-value> ] , [ <end-value> ] ).

If the verbosity is too annoying, you could also say that the wrapper is only required when it would otherwise be ambiguous. In other words, say that <start-value> and <end-value> can contain any value syntax other than top-level commas (and square brackets if you go with the terser option), so that mix(70%, 0%, 100%) works without wrapping but mix(70%, value(a, b, c), value(d, e, f)) needs to be wrapped.

@LeaVerou
Copy link
Member

LeaVerou commented Oct 1, 2021

Brainstorming: What about from() and to()? mix(<percentage> from(<value>) to(<value>))?
But whatever syntax we come up with, it would be nice to be able to avoid the nested parens when the values are unambiguous.

@Loirooriol
Copy link
Contributor

Note that grid-template-columns/rows already use []-block values. I'm not aware of any property using ()-block values (AFAIK parentheses are only used in functions). So mix( <percentage> , ( <start-value> ) , ( <end-value> ) ) might be better.

About from() and to(), they could work here but not for #5055 or #6704.

@nex3
Copy link
Contributor Author

nex3 commented Oct 1, 2021

@Loirooriol grid-* values would still work here, you'd just double-nest the square brackets. At the risk of bringing in another active debate, it's worth noting that the reason it uses square brackets rather than parens is because having parens in plain CSS would wreak unholy havoc with Sass's parser.

@Crissov
Copy link
Contributor

Crissov commented Oct 2, 2021

  • mix(<percentage> @from <value> @to <value>)
  • mix(<percentage>, <value> -- <value>)

@Loirooriol
Copy link
Contributor

@Crissov Consider list-style: mix(0%, inside -- -- outside). The -- is a valid identifier, so does it interpolate from inside -- to outside, or from inside to -- outside? Ambiguous.

@Loirooriol
Copy link
Contributor

A top-level ! is invalid in a <declaration-value>, just like ;. Would mix(<percentage> ! <start-value> ! <end-value> ) be better for SASS and similar tools?

But I'm not convinced we should avoid ;. After all, --lorem: ipsum(0%; sit; amet) is a perfectly valid CSS declaration. I think the tools should just fix their parser. And it's not like all tools would break, e.g. geany's syntax highlighter seems fine:

@tabatkins
Copy link
Member

Yeah, given the existence of custom properties, semicolon and ! are the only possible inline separators; every other possible character is valid CSS property syntax in at least some context.

Wrapping delimiters, like from() and to(), are fine tho, and those names in particular have a nice connection to Animations. It's a bit heavy-weight for smaller values, tho. It would suggest the possibility of further expansion, with a step(%, <any-value>) that lets you set up a full set of inline keyframes and get the value at a particular progress %. ^_^

@nex3
Copy link
Contributor Author

nex3 commented Oct 4, 2021

A top-level ! is invalid in a <declaration-value>, just like ;. Would mix(<percentage> ! <start-value> ! <end-value> ) be better for SASS and similar tools?

No, the issue is that these tools rely on similar parsing logic to CSS, so they won't parse ! in a CSS value specifically because it's not valid in any existing property.

Yeah, given the existence of custom properties, semicolon and ! are the only possible inline separators; every other possible character is valid CSS property syntax in at least some context.

That's not strictly true—not all <declaration-value>s are useful in mix(), since its value isn't directly accessible to JavaScript the way custom property values are. It has to be included in some registered CSS property's value, which means that any token that's not part of an existing well-known CSS property value (such as @from or --) is usable, at the cost of never being able to use it in any other value context in the future.

@mirisuzanne
Copy link
Contributor

Just brainstorming: A lot of languages (and the css syntax notation) use | for some variant of "or" — a delimiter between options. The concept here is not exact in all cases, but it is similar in some ways.

@FremyCompany
Copy link
Contributor

FremyCompany commented Oct 6, 2021

I like | as well
But I feel like maybe || would be even nicer? That's what Brian and me used in our feu Custom Properties alternate draft.

@nex3
Copy link
Contributor Author

nex3 commented Oct 6, 2021

For the record, | is still likely to be somewhat of a roadblock for tooling—it has the benefit of not already being a statement separator, so naive parsers won't choke on it as easily as ;, but it's not already used in a value context so any parser that does any sort of validation will still need to push out updates in order to support it.

@fantasai fantasai added the css-values-4 Current Work label Jan 26, 2022
@fantasai
Copy link
Collaborator

fantasai commented Jun 9, 2022

Any serious CSS tooling should have already built in pairing of parens, brackets, and braces, which should render this a non-issue. This is a core piece of CSS's forwards-compatible parsing rules, and it's needed for correct error-handling and for correct error-highlighting. What specific tools are so naive as to choke on this, and is the breakage really so bad that we need to alter core CSS to compensate?

Fwiw, I'm very strongly against any syntax that requires wrapping in parentheses or brackets, this is just very noisy and annoying, and if it's optional it's also confusing. If we're picking a different delimiter, it needs to be one that can function like a comma. (And for that purpose, semicolon is the most natural one to use: it is effectively defined as a stronger comma in natural language usage, and in CSS it is guaranteed to not cause a syntactic conflict in the future.)

@nex3
Copy link
Contributor Author

nex3 commented Jun 9, 2022

Any serious CSS tooling should have already built in pairing of parens, brackets, and braces, which should render this a non-issue.

Why should it? If a tool wants to naïvely determine the start and end of a given declaration, currently it can do so by simply consuming tokens until it hits ; or } and realistically that'll function correctly for essentially all real-world CSS. Yes, there are custom-property edge-cases that will break, but I don't think any of them have seen widespread use since Polymer entered maintenance mode. And that's to say nothing of the undoubtedly countless hacked-together tools that don't even tokenize the input and just use regular expressions to parse.

What specific tools are so naive as to choke on this, and is the breakage really so bad that we need to alter core CSS to compensate?

Sass is a specific example of a tool that will choke on this, although not so much because it's naïve as that it needs to do a semantic parse of all expression syntax.

The Sass breakage isn't bad enough to be worth altering CSS on its own, since we could easily add support for this new syntax. The core objection here is that it would break many tools—particularly small, ad hoc tools that are likely maintained by individual organizations rather than widely-used open source tools which have stronger pressures on them to support every edge case.

@astearns
Copy link
Member

astearns commented Mar 7, 2024

Given the resolution here #9539 (comment) I believe we have opted-in to the tooling pain of using semicolons as delimiters

@astearns astearns removed the Agenda+ label Mar 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Unsorted regular
Development

No branches or pull requests

9 participants