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] Define value syntax that limits <integer>, <number>, <length>, etc. to ranges #355

Closed
AmeliaBR opened this issue Jul 28, 2016 · 25 comments

Comments

@AmeliaBR
Copy link
Contributor

Many properties only accept positive values. Negative values are illegal, and are parse errors. This is currently only defined in prose for the relevant property. Examples: width, height, line-height.

In contrast, other properties have logical bounds, but values outside these bounds are parsed as normal and only clamped at used value time. Examples: opacity, numeric parameters in color functions.

I'm sure it would be useful for both authors and implementers if the property value syntax explicitly indicated whether negative values would be a parse error or not. That requires new value types in CSS Values & Units.

I'm not sure if there are any other common "illegal value" restrictions currently defined in prose, but it's worth looking around to see if there are, and if they can also be standardized into the value definition syntax.

@tabatkins
Copy link
Member

Well, "positive" is only allowed for integers, not numbers or dimensions, because it constitutes an open range otherwise, which is informally disallowed. We do use non-negative (sometimes paired with prose that floors it at some non-zero value), but that's harder to express easily.

@AmeliaBR
Copy link
Contributor Author

Mathematically, "positive" usually means zero or greater, which is what I was thinking of, although depending on how the CSS parser handles -0, you might need some extra text in there.

"non-zero positive integer" would be another possible type, if that's actually required anywhere.

@frivoal
Copy link
Collaborator

frivoal commented Jul 29, 2016

"non-zero positive integer" would be another possible type, if that's actually required anywhere.

It is: #341 (comment)

@astearns astearns added the css-values-4 Current Work label Jul 29, 2016
@tabatkins
Copy link
Member

Mathematically, "positive" usually means zero or greater, which is what I was thinking of, although depending on how the CSS parser handles -0, you might need some extra text in there.

That's not really true in my experience? Zero is neither positive nor negative, and there's a lot of stuff backing that up: the relatively common usage of "non-negative" in precise technical contexts, the implementations of sign() functions in various languages, the fact that +0 and -0 are mathematically equivalent, etc. CSS has been pretty precise about this, because we've gotten bug reports about "why isn't 0 valid?" when we were imprecise and just used "positive". At best, whether 0 is considered "positive" or not is ambiguous and context-sensitive.

@AmeliaBR
Copy link
Contributor Author

AmeliaBR commented Aug 3, 2016

At best, whether 0 is considered "positive" or not is ambiguous and context-sensitive.

OK, I agree that a completely unambiguous terminology would be better. But the rest of my suggestion still stands: can we define <non-negative-integer>, <non-negative-length>, etc., data types, so that these restrictions do not have to be defined in prose?

@fantasai
Copy link
Collaborator

fantasai commented Oct 24, 2017

I don't have a problem with this in theory, but in practice <non-negative-integer> eats up a much larger part of the measure. For grammars with more than a handful of possible value components, it triggers more wrapping and makes them harder to read. So while defining these limits in prose is maybe not ideal, I'm less than enthusiastic about adopting these new types. :(

@tabatkins
Copy link
Member

We can go with shorter names; <p-integer>, <nn-integer>, etc. Unsure if that's worthwhile.

@AmeliaBR
Copy link
Contributor Author

Yes, I'm certainly not stuck on the syntax. I just want the full parsing requirements to be unambiguously defined by the grammar.

Another approach would be to express it numerically, something like <length >= 0>, <integer > 0>, except without > characters! <length gte 0> and <integer gt 0>?

@Crissov
Copy link
Contributor

Crissov commented Oct 25, 2017

You could use more vulgar terms. They come with varying definitions outside CSS, but would of course have an unambiguous one inside:

  • ℤ = <whole-number>, <integer>
  • ℕ = <natural-number>, <natural-integer> – either positive or non-negative
  • ℕ* = ℕ⁺ = ℕ₁ = ℤ⁺ = {1, 2, 3, …}: <ordinal>, <ordinal-number>, <ordinal-integer>, <rank-integer> … – positive
  • ℕ⁰ = ℕ₀ = {0, 1, 2, …}: <cardinal>, <cardinal-number>, <cardinal-integer>, <size-integer>, <set-integer>, <counting-number>, <count-integer> … – non-negative

Thinking @AmeliaBR's latest idea further, <length min 0>, <length max 100% abs>, <integer 0..255> show different syntax that should be readable instantly for many people.

@AmeliaBR
Copy link
Contributor Author

The discussion on clamping column width values (#1741) made me think of this again.

One final option for terminology: Take a cue from WebIDL, and use "unsigned" for values that cannot be negative. So it would be <unsigned-integer>, <unsigned-number>, <unsigned-length-percentage>, etc. For the rare cases: <non-zero-unsigned-integer>.

That said, I still think I prefer an explicit constraints syntax, like <length min 0>, as it is easier to understand on its own.

Regardless of the syntax, I still would very strongly like to add this option to the CSS grammar, so that all parser constraints on values can be expressed in the grammar.

So, I'm requesting this for the WG agenda, with the following questions for discussion:

  • Should the CSS Value Definition Grammar be expanded to allow it to express all parser-level constraints on allowed values?

  • If so, how should the constraints be expressed?

    1. By adding new data type names for all existing constrained types (non-negative numbers, non-negative lengths, strictly positive integers, etc.)?
    2. Or, by adding a generic way of indicating maximum and minimum values for any numeric type?

If we can get a resolution on those points, then we can bikeshed the exact syntax in a more focused way.

@css-meeting-bot
Copy link
Member

The Working Group just discussed Define <positive-integer>, <positive-number>, <positive-length>, etc. sub-types, and agreed to the following resolutions:

  • RESOLVED: Extend value definition syntax to handle value ranges and possibly other syntactic restrictions, syntax TBD
The full IRC log of that discussion <dael> Topic: Define <positive-integer>, <positive-number>, <positive-length>, etc. sub-types
<dael> github: https://github.com//issues/355
<dael> AmeliaBR: A couple years ago there was discussion and it got lost in bikeshedding syntax. I wanted to at least get a clear opinion from the group if the idea is good.
<dael> AmeliaBR: I'd like to see if that when we have properties with constraints enforced by the parser, most common is no negative values, there is a way to explain that in the grammar rather then only prose.
<dael> AmeliaBR: It would be convenient for people impl parsers if the grammar covered everything esp now that Houdini is exposing the value syntax. Might be time to be more strict about value definition language.
<florian> +1, makes total sense to me
<dael> AmeliaBR: I was hoping to get a resolution that it would be a good idea to extend value definition lang to cover all constraints from the parser.
<dbaron> "all constraints that can be enforced by the parser" sounds like it might be a little much
<dael> AmeliaBR: I had a second question on narrowing down approaches.
<astearns> +1 from me as well
<dael> fantasai: I don't think we'll be able to put in all parsing restrictions because I remember there are restrictions not in the grammar that aren't just about limiting range of numbers. We won't get to 100% but it should be possible to put range restrictions. If this is author exposed syntax that might be important.
<TabAtkins> positive-int, and gez-int and gez-number seem very fine, along with gez-length/etc
<astearns> define gez?
<dael> florian: I think we could take somewhere between...in V&U we define non-negative ranges and houdini relies on that. If it's not the case already in indiviual specs we have something that looks like int but with constraints we deinfe anew type. Doesn't have to be shared in V&U. That's not actionable, that's how to write. The actionable part I'm all for it.
<TabAtkins> greater-equal-zero
<TabAtkins> p-integer, nn-integer
<dael> astearns: I'm all for having this defined in the grammar and not lost in the prose. I don't care what names we use particularly.
<dael> fantasai: I'd like the syntax to be reasonably readable and not so long that the grammar is hard to read. non-negative-integrer is really long.
<dael> fantasai: Every time we throw in one of these it wraps and it's hard to read. It seems like a great idea but I haven't seen a proposal for yes we should do it this way. If this is exposed in Houdini we should put thought in understandable and usable like we do for other property values we define.
<fantasai> s/one/one or four/
<dael> astearns: I think consensus is this is a good direction to take. Second question?
<fantasai> s/wraps/gets long and maybe wraps/
<dael> AmeliaBR: My initial idea was new name types but in the discussion there was a suggestion of introducing it more as a modifying constraint within the type. Syntax that looked readable was make it look like a HTML attribute.
<dael> AmeliaBR: It's very nice and readable. Other aspect is it's open ended. Could be a benefit, could be a negative. Do people like the idea of adding a general way of adding constraints or is it something we want to keep to named types?
<dael> TabAtkins: I hadn't seen that comment, I'll have to think about that.
<florian> I am not sure, but I am intrigued
<dael_> astearns: prop: we will add more terms tot he grammar to describe value ranges and such, but approach is in the air.
<dael_> astearns: Objections?
<fantasai> proposed resolution: Extend value definition syntax to handle value ranges and possibly other syntactic restrictions, syntax TBD
<dael_> RESOLVED: Extend value definition syntax to handle value ranges and possibly other syntactic restrictions, syntax TBD
<dbaron> I need to head out now, but I'll see you next week...
@AmeliaBR
Copy link
Contributor Author

AmeliaBR commented Sep 18, 2018

FYI, I found a case of a numeric property defined to have a fixed range that isn't just non-negative or strictly positive. stroke-miterlimit was defined to accept a number (integer or decimal) that it must be equal to or greater than 1.

AKA <number --gte 1>, <number min=1>, <number [1,]> or however it ends up defined syntactically!

Of course, only one browser (Firefox) currently implements that exact rule as a parser-time check, see w3c/svgwg#545

Edit: as described in the linked issue, the property is now defined to accept any non-negative value.

@AmeliaBR
Copy link
Contributor Author

I'd like to get a resolution on this at the February F2F.

Specifically, I'm advocating for the syntax that uses SGML-style attributes (<number min=1 max=10>). It's a familiar syntax for pretty much anyone who is working with CSS, it is explicit about the meaning, and it has the potential to be extended in the future.

For now, we would be adding min and max attributes to all numeric, length, and other quantity data types, including combinations such as <length-percentage>.

The min and max values would be inclusive. As Tab mentions earlier in the thread, we don't want open-ended bounds for non-integer values (e.g., to allow 0.00000000001 but not 0) because that gets into messy areas of numeric precision. For integer values, it is easy to just shift the minimum/maximum to the next allowed value (that is, to specify <integer min=1> instead of "integer greater than 0").

I haven't had a chance to do a comprehensive review of how many properties this would effect, but here are some examples from CSS Fonts Level 4:

  • font-size

    <absolute-size> | <relative-size> | <length-percentage min=0>

  • font-weight:

    [normal | bold | <number min=1 max=1000>]| bolder | lighter

  • font-stretch:

    normal | <percentage min=0%> | <font-stretch-keyword-value>

  • font-style

    normal | italic | oblique <angle min=-90deg max=90deg>?

As discussed previously, this syntax only covers parser-enforced restrictions on values, not clamping that happens at computed-value or used-value time. Specifically, any value that doesn't meet these constraints on the data type would make the surrounding declaration invalid, per CSS Syntax:

After each construct (declaration, style rule, at-rule) is parsed, the user agent checks it against its expected grammar. If it does not match the grammar, it’s invalid, and gets ignored by the UA, which treats it as if it wasn’t there at all.

Currently, the parser-level constraints on CSS values are defined by prose that states that certain values are invalid. E.g., the prose for font-weight currently says "Only values greater than or equal to 1, and less than or equal to 1000, are valid, and all other values are invalid."

The proposed change would encode those constraints directly in the CSS Values grammar.

@fantasai
Copy link
Collaborator

I'd prefer to use mathematical range notation. It's a lot more compact, and part of keeping these grammars readable is keeping them compact enough to be visually parsed.

<angle [-90deg,90deg]>

Alternately some form of colloquial range notation (same rationale).

<integer 1+> <integer 0+> <percentage -100% to 100%> <percentage 0 to 100%>

(Maybe replace "to" with a proper n-dash. ;)

@AmeliaBR
Copy link
Contributor Author

AmeliaBR commented Jan 29, 2019

@fantasai Okay, so that's two additional syntaxes, for three alternatives so far.

So people can really compare, here's what they look like for the font properties I used in my comment above, along with my summary of pros and cons:

Attribute notation

  • font-size: <absolute-size> | <relative-size> | <length-percentage min=0>

  • font-weight: [normal | bold | <number min=1 max=1000>] | bolder | lighter

  • font-stretch: normal | <percentage min=0%> | <font-stretch-keyword>

  • font-style: normal | italic | oblique <angle min=-90deg max=90deg>?

Pros

  • familiar syntax
  • easy to read
  • extensible to other types of constraints

Cons

  • verbose

Bracket range notation

  • font-size: <absolute-size> | <relative-size> | <length-percentage [0,]>

  • font-weight: [normal | bold | <number [1,1000]>] | bolder | lighter

  • font-stretch: normal | <percentage [0%,]> | <font-stretch-keyword>

  • font-style: normal | italic | oblique <angle [-90deg, 90deg]>?

Pros

Cons

  • similar to the syntax used for describing a number of repeated tokens
  • the single-sided bounds syntax ([0,] for zero and up) may be confusing for those not familiar with mathematical range notation

Human-readable range notation

  • font-size: <absolute-size> | <relative-size> | <length-percentage 0+>

  • font-weight: [normal | bold | <number 1 to 1000>] | bolder | lighter

  • font-stretch: normal | <percentage 0%+> | <font-stretch-keyword>

  • font-style: normal | italic | oblique <angle -90deg to 90deg>?

Pro

  • compact
  • written the way you would read it

Cons

  • The + notation can get lost among % signs or units.
  • No syntax for a maximum bound without a minimum bound (but I don't think we have any use case for this).

(Maybe replace "to" with a proper n-dash. ;)

Nope. The whole idea is to make a grammar that is easier to auto-parse! Subtle typographic niceties not allowed! Especially because I want to eventually use the chosen syntax within author-supplied values to Houdini APIs.

@dbaron dbaron changed the title [css-values] Define <positive-integer>, <positive-number>, <positive-length>, etc. sub-types Feb 12, 2019
@tabatkins
Copy link
Member

  • the single-sided bounds syntax ([0,] for zero and up) may be confusing for those not familiar with mathematical range notation

Would it be troublesome to do [0,∞]? We promised to keep CSS grammar ASCII-only, but not the description of its syntax. ^_^ (And I'm okay with an ∞ showing up in Houdini code.)

@fantasai
Copy link
Collaborator

@tabatkins I thought about that as well. :) I say we go ahead and use it, but also accept the missing infinity version so that people who have trouble typing it don't have to.

@Crissov
Copy link
Contributor

Crissov commented Feb 25, 2019

Brackets and dots notation

An ellipsis made of three dots ... (not U+2026 ) could stand in for an infinity sign.

  • font-size: <absolute-size> | <relative-size> | <length-percentage [0, ...]>
  • font-weight: [ normal | bold | <number [1, 1000]> ] | bolder | lighter
  • font-stretch: normal | <percentage [0%, ...]> | <font-stretch-keyword>
  • font-style: normal | italic | oblique <angle [-90deg, 90deg]>?

Dots notation

This could be coupled with two dots to indicate a closed range, which in turn is just a variation of the human-readable range notation with .. substituting to and ... for +.

  • font-size: <absolute-size> | <relative-size> | <length-percentage: 0 ...>
  • font-weight: [ normal | bold | <number: 1 .. 1000> ] | bolder | lighter
  • font-stretch: normal | <percentage: 0% ...> | <font-stretch-keyword>
  • font-style: normal | italic | oblique <angle: -90deg .. 90deg>?
@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed Adding min/max constraints, and agreed to the following:

  • RESOLVED: We will use the bracket range notation
The full IRC log of that discussion <gregwhitworth> Topic: Adding min/max constraints
<gregwhitworth> AmeliaBR: currently we have something like length-percent and in the prose it says negative values are invalid
<astearns> github: https://github.com//issues/355#issuecomment-458324757
<gregwhitworth> AmeliaBR: the idea is to get that into the actual syntax grammar
<gregwhitworth> AmeliaBR: especially with various houdini APIs we're providing authors with access to the syntax
<gregwhitworth> AmeliaBR: the issue is to discuss what this syntax looks like
<gregwhitworth> AmeliaBR: my proposal was to look like something like sgml attributes, we're using angle brackets for data types
<gregwhitworth> AmeliaBR: fantasai concern is that that can get verbose
<gregwhitworth> AmeliaBR: if you go down to the second to last issue I have the different options with 4 real world examples
<gregwhitworth> AmeliaBR: Any pros/cons - I've listed mine but would like to hear peopl'es feedback
<gregwhitworth> fantasai: I like my proposal
<gregwhitworth> fantasai: I really don't want to make things too verbose, the more the grammar has to wrap the harder it is to read
<gregwhitworth> fantasai: I
<gregwhitworth> fantasai: I prefer the more human readible version
<astearns> https://github.com//issues/355#issuecomment-458324757
<gregwhitworth> TabAtkins: shows options on screen
<gregwhitworth> TabAtkins: explains the various proposals in the link above
<gregwhitworth> fantasai: a min in human readible could be 0+
<gregwhitworth> TabAtkins: I'm most a fan of the bracket range syntax
<gregwhitworth> fantasai: if you're going to use multipliers it uses similiar syntax
<gregwhitworth> TabAtkins: this is already in the syntax
<gregwhitworth> TabAtkins: I agree with the idea in general
<gregwhitworth> TabAtkins: I agree with AmeliaBR that with Houdini we need to provide access to this
<gregwhitworth> heycam: A non syntax question
<gregwhitworth> heycam: when we have prose that restricts these values, when we have calc expressions, when we have negative inside the calc - would a change to this syntax make some values invalid earlier?
<gregwhitworth> TabAtkins: This shouldn't change anything this is just moving the prose into the grammar
<gregwhitworth> TabAtkins: calcs are still valid and clamp to the range
<gregwhitworth> heycam: if you have a property number 1-1000
<gregwhitworth> heycam: and you use any calc inside that
<gregwhitworth> TabAtkins: yep, that should work
<gregwhitworth> astearns: does anyone have any objections to bracket notation
<gregwhitworth> astearns: I would prefer to have explicit rather than empty
<gregwhitworth> TabAtkins: what about writing infinity rather than the symbol
<gregwhitworth> fantasai: no
<gregwhitworth> iank_: are we allowing the word infinity?
<gregwhitworth> iank_: I'm biased to the Javascript
<gregwhitworth> TabAtkins: what about both?
<gregwhitworth> iank_: I'm fine with both
<gregwhitworth> AmeliaBR: that sounds the best for me
<gregwhitworth> AmeliaBR: the infinity symbol is nice in a spec but not necessarily for typing in code
<myles_> +1 to what AmeliaBR said
<gregwhitworth> heycam: rather than brackets and commas you can use ..
<gregwhitworth> TabAtkins: some languages include two dots others use three dots
<gregwhitworth> gregwhitworth: I would prefer no on that
<TabAtkins> s/TabAtkins/heycam/
<gregwhitworth> AmeliaBR: as fantasai noted the brackets are known in CSS in the grammar
<gregwhitworth> iank_: also the ... may get confused with the destructioring in JS
<gregwhitworth> TabAtkins: we will go with the bracket version and allow Infinity and the infinity symbol
<gregwhitworth> TabAtkins: I would never propose the inifinty symbol for CSS itself, this is for syntax
<gregwhitworth> florian: Bikeshed feature request, convert infinity word to symbol
<gregwhitworth> fantasai: there is an infinity code and ampersand version
<TabAtkins> &infin;
<gregwhitworth> fantasai: what's the case sensitivity of the inifnity keyword?
<gregwhitworth> TabAtkins: in JS it's Infinity
<gregwhitworth> fantasai: as a string?
<gregwhitworth> TabAtkins: it would be number [1, Infinity]
<AmeliaBR> Proposal: Use the bracket range notation (from the issue), but with infinite ranges (no max/min) represented by either `Infinity` or &infin; (or negative thereof)
<gregwhitworth> AmeliaBR: it's not a string it's a token within the syntax
<gregwhitworth> fantasai: question, is our sytax types case sensitive
<gregwhitworth> TabAtkins: the Houdini syntax cares
<gregwhitworth> fantasai: yeah we're consistent in our specs but I was curious
<gregwhitworth> astearns: any objections to the proposal
<TabAtkins> `syntax: "big | BIGGER"` in registerProperty() is already case-sensitive
<gregwhitworth> RESOLVED: We will use the bracket range notation
@svgeesus
Copy link
Contributor

Bikeshed needs to be updated to work wit this, apparently

@AmeliaBR
Copy link
Contributor Author

Bikeshed issue: speced/bikeshed#1441

I'll make the tracking issue for the edits once that is resolved.

@tabatkins
Copy link
Member

Bikeshed's updated, plz make tracking issues @AmeliaBR ^_^

@AmeliaBR
Copy link
Contributor Author

Darnit. I had such a good excuse for not working on this. Ok, I'll tackle that this weekend.

@AmeliaBR
Copy link
Contributor Author

AmeliaBR commented May 5, 2019

Ok, change of plans. I decided it's just as easy to make the edits as to make a few dozen issues. But I came up with a stylistic question:

Should I only be adding the bracket range notation to the blue-box definition, or also to prose references to syntax parts? I'm currently adding it in where there is a definition list that breaks out the syntax pieces, but am not otherwise adding it to prose.

I'm also leaving in all the prose restrictions (e.g. "negative values are invalid" or "negative values are not allowed").

@tabatkins
Copy link
Member

Should I only be adding the bracket range notation to the blue-box definition, or also to prose references to syntax parts? I'm currently adding it in where there is a definition list that breaks out the syntax pieces, but am not otherwise adding it to prose.

I'm copying it to the dts defining individual grammar chunks; it's a relevant piece of information, and readers are well-served by surfacing it right at its actual point of definition.

I am removing prose restrictions that are entirely obviated by the grammar change, tho; we don't say in prose that a value "must be a length, or else it's invalid", etc., so when the grammar expresses that it's non-negative, no need to say that explicitly again in prose.

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