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] Quirky lengths and math expressions #4874

Closed
emilio opened this issue Mar 14, 2020 · 11 comments
Closed

[css-values] Quirky lengths and math expressions #4874

emilio opened this issue Mar 14, 2020 · 11 comments

Comments

@emilio
Copy link
Collaborator

emilio commented Mar 14, 2020

Quirks mode allows to specify lengths without units, so do some SVG properties like stroke-width. However, when you mix this with calc() units, stuff gets complex very fast (calc() becomes ambiguous) and the results across browsers become a bit bizarre.

Trivial example (link):

<!doctype html>
<div id=a style="stroke-width: calc(2 * 2)"></div>
<div id=b style="stroke-width: calc(2px * 2)"></div>

All browsers agree on the computed value of #b, being 4px as expected. For #a, we get:

  • Firefox: Computed value is the initial value (1px) because the expression doesn't parse (Firefox doesn't propagate this quirk into calc()).
  • WebKit: It parses, computed value is 0px.
  • Blink: It parses, computed value is 2px.

I think having the ambiguity of whether a <number> should be treated something is a <length> or not inside math expressions is not worth it and it's only going to get more complex as we add more math functions. Thus I'd like to standardize on Firefox's behavior, if other people agree.

Otherwise we could try to parse / resolve calc() both as a <number> and a <length-percentage>, I guess, which would allow for the previous example, but would disallow stuff like calc(4 * 100% + 4) or such...

Relevant links:

cc @tabatkins @lilles @andruud

@emilio
Copy link
Collaborator Author

emilio commented Mar 14, 2020

cc @smfr too :)

@emilio
Copy link
Collaborator Author

emilio commented Mar 14, 2020

Also, note that I really think that Firefox's behavior is more desirable for the "regular length in quirks mode case". I think the "svg-originated property" case is a bit more debatable, but I still think it's better.

@plinss
Copy link
Member

plinss commented Mar 14, 2020

Huge +1 on this. Quirks mode was designed for backwards compatibility for features that pre-dated 1998. It was never intended to propagate into anything new. All new features should be standards mode only.

@AmeliaBR
Copy link
Contributor

We already have agreement that inside a calc expression, numbers are always treated as numbers, not lengths. So a calc(10 + 2px) would always be invalid.

The question is, if the final evaluated result is a number (calc(100/3)), is that OK? Can it be mapped from number to length after the calculation is complete, or does the mapping need to happen at parsing time?

so do some SVG properties

For SVG 2, we have two rules for this:

  • For SVG-specific properties like stroke-width, the property grammar now explicitly allows a <number> type as an alternative to a <length> or <length-percentage>. So, a calc expression that evaluates to a number should be fine. (Actual browser support for calc in SVG stuff is a mess of inconsistency, though).

  • For properties defined by other CSS specs, like font-size, unitless lengths are allowed in the SVG presentation attribute only, and the SVG 2 spec currently explains this by an algorithm that upgrades all <length> values in the grammar to <length>|<number>, and so on.

    But I'm not sure how implementable that is if we combine it with calc() expressions and things like TypedOM that need access to a standard serialization of the specified value. So if you can think of a better way to define this, consistent with how you want to handle quirks mode, that would probably work here, too.

@emilio emilio changed the title Quirky lengths and math expressions [css-values] Quirky lengths and math expressions Mar 15, 2020
@emilio
Copy link
Collaborator Author

emilio commented Mar 15, 2020

For SVG-specific properties like stroke-width, the property grammar now explicitly allows a <number> type as an alternative to a <length> or <length-percentage>. So, a calc expression that evaluates to a number should be fine. (Actual browser support for calc in SVG stuff is a mess of inconsistency, though).

I think what Firefox implements is basically this, but with <number-token> instead of <number>. Supporting calc() resolving to a number would be doable, but not sure it's worth doing, because it's the wrong thing to do for quirks, and I'd rather not introduce yet another svg-specific parsing mode.

@faceless2
Copy link

For SVG-specific properties like stroke-width, the property grammar now explicitly allows a <number> type as an alternative to a <length> or <length-percentage>. So, a calc expression that evaluates to a number should be fine. (Actual browser support for calc in SVG stuff is a mess of inconsistency, though).

My understanding of this is a little different. For non-quirks mode:

  1. Dimension properties specified as presentation attributes can be specified as numbers or lengths - both<line stroke-width="2"> and <link stroke-width="2px"> mean the same thing.

  2. But if the same properties are specified as CSS, which includes the "style" attribute, then they are parsed as CSS declaration lists, are subject to CSS parsing rules and units are required. So you can do <line style="stroke-width: 2px"> but not <line style="stroke-width: 2">

This describes the behaviour of Firefox, Webkit etc. for attributes like width, x, r etc.

If quirks mode allows length properties to be parsed without units in CSS, then I think that really needs to apply to all length properties - regardless of which specification they're defined in. So <line style="stroke-width: 2"> is as valid as <rect style="width: 200"> or <text style="font-size: 20">.

What this means for "calc" I don't know. Personally I completely agree with @plinss on this, it should be invalid. You can't evolve quirks mode to keep up with changes in the specification.

But, if the decision is made that <div style="width: calc(300 + 3)"> is valid, then I think you necessarily have to allow <line style="stroke-width: calc(300 + 3)">. Treating them differently depending on where they're defined is going to cause problems


Additional point, very specific to SVG2. This states all presentation attributes are parsed using the grammar and types defined in CSS, modified so that wherever<length> is allowed, you're also allowed <number>. My reading of this is that <line stroke-width="calc(20px + 20px)"> is valid in SVG2, although it's certainly not in SVG1 and this syntax is unsupported in any browser. As @emilio has already pointed out, it's also impossible to modify this grammar to allow numbers where a length is allowed. It's quite possible I've got this wrong, but perhaps this section of the SVG2 spec might benefit from clarification.

@tabatkins
Copy link
Member

Firefox has the correct behavior. Quirky lengths aren't any different from unitless zeros - inside a calc(), they're a "number", and the type-checking rules don't allow numbers to be added to non-numbers, etc.

Both Blink and WebKit are wrong, and wrong in bizarre and clearly incorrect ways.

Amelia is right that properties which are defined with an explicit <number> in their grammar (which then interpret it as a px length) should accept calc(2 * 2), and interpret it as 4px. But without that, the quirky-length behavior is a parsing quirk like unitless zeros, and doesn't allow length-accepting properties to take a calc() that resolves to a number.

@AmeliaBR
Copy link
Contributor

Again, for SVG there are two different sets of behavior: properties like stroke-width which allow unitless numbers anywhere, including in CSS declarations, versus those (like font-size) that only allow it in presentation attributes.

I agree that it makes sense to harmonize the second case with other quirky CSS parsing. We can change the SVG spec to link to wherever in CSS that's defined, and just say that SVG presentation attributes use quirky parsing.

But stroke-width (and stroke-dasharray and a bunch of other SVG-specific style properties) are different. They take unitless numbers regardless of whether they are defined in attributes or in style declarations. In SVG 1 it was handwavy and spec'd that numbers are valid lengths for these properties. But it's now defined explicitly in SVG 2 using CSS grammar: numbers and lengths are parsed as separate things, but either are valid. Numbers should only be converted to length at used value time, similar to how line-height works.

That seems to be how it works in Chromium: numbers and calc resulting in numbers are both fine in the stroke properties, regardless of attributes or style declarations. Firefox is inconsistent with the spec by only allowing literal numbers. But again, they support it in both style properties and attributes. Test case

Meanwhile, for font-size (same test case link), both browsers are consistent in not supporting unitless numbers for CSS declarations, but allowing literal numbers in the attributes. Chromium has the same buggy behavior for calc in attributes as Emilio described above for quirky lengths: it's accepted at parse, but then at computed time it becomes font-size: 0px. (Firefox just ignores the calc as invalid.) So, at least we already have consistency that this is being treated the same as other quirky CSS parsing!

@AmeliaBR AmeliaBR added the SVG label Mar 15, 2020
@faceless2
Copy link

My error, I'd missed that stroke-width in SVG is explicitly defined to accept a number in the grammar. For reference I think the complete list of properties defined in SVG where the grammar defines a number can represent a length is:

  • stroke-width
  • stroke-dasharray
  • stroke-dashoffset

Unfortunately each of these is also defined in css-fill-stroke-3 as taking a <length-percentage> only - I know that spec isn't implemented by anyone yet, but this inconsistency should probably be resolved.

@emilio emilio added the Agenda+ label Mar 17, 2020
@lilles
Copy link
Member

lilles commented Apr 3, 2020

This is strictly not about quirkiness in Blink, it is about incorrectly allowing calc expressions which mix percentages and numbers, lengths and numbers, and all three of lengths, percentages and numbers.

I have a CL up for review in Blink (which still accepts calc() for <number> which should be per spec):

https://chromium-review.googlesource.com/c/chromium/src/+/2134251/

chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Apr 3, 2020
We allowed calc expressions combining numbers and lengths, numbers and
percentages, and even a combination of numbers, percentages, and
lengths. None of those are allowed per the CSS Values and Units spec,
and it made it possible to combine user units, lengths, and percentages
into the same calc() for certain SVG CSS properties and attributes.

See also: w3c/csswg-drafts#4874

This improves SVG interop with Firefox. Firefox does not support calc()
for numbers, though.

Bug: 1061714
Change-Id: I9e5c492122242e51064310a40e28a233530e357c
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Apr 3, 2020
We allowed calc expressions combining numbers and lengths, numbers and
percentages, and even a combination of numbers, percentages, and
lengths. None of those are allowed per the CSS Values and Units spec,
and it made it possible to combine user units, lengths, and percentages
into the same calc() for certain SVG CSS properties and attributes.

See also: w3c/csswg-drafts#4874

This improves SVG interop with Firefox. Firefox does not support calc()
for numbers, though.

Bug: 1061714
Change-Id: I9e5c492122242e51064310a40e28a233530e357c
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Apr 3, 2020
We allowed calc expressions combining numbers and lengths, numbers and
percentages, and even a combination of numbers, percentages, and
lengths. None of those are allowed per the CSS Values and Units spec,
and it made it possible to combine user units, lengths, and percentages
into the same calc() for certain SVG CSS properties and attributes.

See also: w3c/csswg-drafts#4874

This improves SVG interop with Firefox. Firefox does not support calc()
for numbers, though.

Bug: 1061714
Change-Id: I9e5c492122242e51064310a40e28a233530e357c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2134251
Commit-Queue: Rune Lillesveen <futhark@chromium.org>
Reviewed-by: Fredrik Söderquist <fs@opera.com>
Cr-Commit-Position: refs/heads/master@{#756226}
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Apr 3, 2020
We allowed calc expressions combining numbers and lengths, numbers and
percentages, and even a combination of numbers, percentages, and
lengths. None of those are allowed per the CSS Values and Units spec,
and it made it possible to combine user units, lengths, and percentages
into the same calc() for certain SVG CSS properties and attributes.

See also: w3c/csswg-drafts#4874

This improves SVG interop with Firefox. Firefox does not support calc()
for numbers, though.

Bug: 1061714
Change-Id: I9e5c492122242e51064310a40e28a233530e357c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2134251
Commit-Queue: Rune Lillesveen <futhark@chromium.org>
Reviewed-by: Fredrik Söderquist <fs@opera.com>
Cr-Commit-Position: refs/heads/master@{#756226}
blueboxd pushed a commit to blueboxd/chromium-legacy that referenced this issue Apr 3, 2020
We allowed calc expressions combining numbers and lengths, numbers and
percentages, and even a combination of numbers, percentages, and
lengths. None of those are allowed per the CSS Values and Units spec,
and it made it possible to combine user units, lengths, and percentages
into the same calc() for certain SVG CSS properties and attributes.

See also: w3c/csswg-drafts#4874

This improves SVG interop with Firefox. Firefox does not support calc()
for numbers, though.

Bug: 1061714
Change-Id: I9e5c492122242e51064310a40e28a233530e357c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2134251
Commit-Queue: Rune Lillesveen <futhark@chromium.org>
Reviewed-by: Fredrik Söderquist <fs@opera.com>
Cr-Commit-Position: refs/heads/master@{#756226}
xeonchen pushed a commit to xeonchen/gecko that referenced this issue Apr 9, 2020
…ec., a=testonly

Automatic update from web-platform-tests
Only allow calc() combinations as per spec.

We allowed calc expressions combining numbers and lengths, numbers and
percentages, and even a combination of numbers, percentages, and
lengths. None of those are allowed per the CSS Values and Units spec,
and it made it possible to combine user units, lengths, and percentages
into the same calc() for certain SVG CSS properties and attributes.

See also: w3c/csswg-drafts#4874

This improves SVG interop with Firefox. Firefox does not support calc()
for numbers, though.

Bug: 1061714
Change-Id: I9e5c492122242e51064310a40e28a233530e357c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2134251
Commit-Queue: Rune Lillesveen <futhark@chromium.org>
Reviewed-by: Fredrik Söderquist <fs@opera.com>
Cr-Commit-Position: refs/heads/master@{#756226}

--

wpt-commits: 2e5ea4313ba76d4d0c66c4798ed25a288ddee254
wpt-pr: 22677
moz-v2v-gh pushed a commit to mozilla/gecko-dev that referenced this issue Apr 10, 2020
…ec., a=testonly

Automatic update from web-platform-tests
Only allow calc() combinations as per spec.

We allowed calc expressions combining numbers and lengths, numbers and
percentages, and even a combination of numbers, percentages, and
lengths. None of those are allowed per the CSS Values and Units spec,
and it made it possible to combine user units, lengths, and percentages
into the same calc() for certain SVG CSS properties and attributes.

See also: w3c/csswg-drafts#4874

This improves SVG interop with Firefox. Firefox does not support calc()
for numbers, though.

Bug: 1061714
Change-Id: I9e5c492122242e51064310a40e28a233530e357c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2134251
Commit-Queue: Rune Lillesveen <futhark@chromium.org>
Reviewed-by: Fredrik Söderquist <fs@opera.com>
Cr-Commit-Position: refs/heads/master@{#756226}

--

wpt-commits: 2e5ea4313ba76d4d0c66c4798ed25a288ddee254
wpt-pr: 22677
@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-values] Quirky lengths and math expressions, and agreed to the following:

  • RESOLVED: Properties that accept quirky lengths accept number token which is converted at parse to pixels
  • RESOLVED: This resolution does not apply to any quirks inside of calc
  • RESOLVED: encourage SVG to follow this approach
The full IRC log of that discussion <dael> Topic: [css-values] Quirky lengths and math expressions
<dael> github: https://github.com//issues/4874
<dael> emilio: This is when should SVG and quirks accept numbers and when shouldn't
<dael> emilio: I think quirks mode shouldn't accept calc but SVG is more debatable.
<dael> emilio: Haven't checked issue today so don't know if there's new comments there
<dael> astearns: One comment from rune where he links to change list for review on Blink
<dael> dbaron: I what emilio is asking is the quirks mode rules that you can omit pixels not apply iside of calc
<dael> TabAtkins: That's what I feel should be happening
<dael> TabAtkins: Effect of quirks mode is these prop are defined to take number as final value and it's interp as pixel. Has no effect on calc b/c doesn't allow 1 + 3px. If your calc ends up as a number it works out.
<dael> TabAtkins: That's what some of the SVG properties do explicitly. If we define quirks as same thing it's a nice consistant system
<dael> emilio: Seems to be Peter said he didn't want it to work. A number inside quirks not to work. I'm ambivelent.
<dael> florian: Logic is quirks was meant to be limited. This is logical extension, yes, but quirks was meant to be as limited as possible.
<dael> AmeliaBR: One complication is as we moved to typedOM and exposing the true computed value not just resolved value things could get a lot messier if we need to keep track of numbers instead of lengths
<dael> emilio: I don't think any engine will struggle. Final number interp as a length
<dael> emilio: I don't know but I suspect fancy calc rules would require keep track but no one impl. You need math there. Calc that resolves to number you can get final at parse.
<dael> TabAtkins: NOt true with the later stuff
<dael> TabAtkins: Re-reading comments. Looks like you suggest quirks accepts number token as the value. So write a literal number but not any expression. No calc, attr, etc
<dael> TabAtkins: That's fine with me. Would like consistent with SVG but since they didn't originally accept calc I suspect could change
<dael> AmeliaBR: SVG presentation attributes where they accept values allowed in regular CSS> Could define presentation attributes are quirky
<dael> TabAtkins: Or jsut number token in grammar. Yeah
<dael> emilio: sgtm. Happy they're consistent
<dael> astearns: Prop: In quirks mode properties don't accept calc
<dael> TabAtkins: IN quirks mode properties that need to be quirky will spec to take a number token and interp as pixels
<dael> AmeliaBR: Spec when fixup happens? How it effect serialization/computing?
<dael> TabAtkins: Don't know today
<dael> emilio: I think all serialize pixels.
<dael> AmeliaBR: I believet hat's true
<dael> emilio: Almost sure webkit and FF do that
<dael> astearns: I don't expect the resoltution effects serialization
<dael> TabAtkins: I could. Have to say when converts to length
<dael> plinss: Should be parse time. Quirks should be as limited as possible and was designed to be phased out. Minimal impact and just at parse time.
<dael> TabAtkins: Fine with me
<fantasai> +1 to plinss
<dael> astearns: Prop: In quirks mode properties that are quirky will be able to take a number token which is interpreted as pixels
<dael> emilio: And so should SVG
<TabAtkins> Confirmed that Blink converts number to px at parse time.
<dael> TabAtkins: Different serialization rules, but otherwise yes
<dbaron> and the point is that "can take a number token" doesn't apply any quirks *inside* of calc()
<dael> AmeliaBR: Not sure how much we need. attribute value will get attribute. CSS serialization can sync
<dael> emilio: We return pixels in specified side
<dael> astearns: All one thing to resolve on? Or are there 3 bits to resolve separately?
<TabAtkins> proposed resolution: Properties that accept "quirky lengths" are defined as having `<number-token>` in their grammar, which is converted at parse-time to a px length. SVG follows along for its presentation attributes.
<dael> emilio: I think...browsers do not agree on quirky SVG so at least 2 resolutions
<dael> astearns: Prop: Properties that accept quirky lengths accept number token which is converted at parse to pixels
<dael> RESOLVED: Properties that accept quirky lengths accept number token which is converted at parse to pixels
<dael> astearns: Second: This resolution does not apply to any quirks inside of calc
<fantasai> +1
<fantasai> make it clear
<dael> emilio: I think that's implied.
<dael> astearns: I'd like to specifically resolve to make it clear
<dael> TabAtkins: sure
<dael> RESOLVED: This resolution does not apply to any quirks inside of calc
<dael> astearns: Browser incompat and presentation attributes following along. Can we resolve?
<dael> emilio: I've never heard of any compat issues
<dael> AmeliaBR: Don't expect issue on compat, but I have to open a separate issue on SVG so we can resolve CSS endorces this and we can add details on SVG
<dael> astearns: Prop: encourage SVG to follow this approach
<dael> RESOLVED: encourage SVG to follow this approach

tabatkins added a commit that referenced this issue Oct 8, 2020
…n parsing, but functions resolving to numbers might be okay due to quirks. #4874
mmso pushed a commit to ProtonMail/WebClients that referenced this issue May 25, 2022
According to [this resolution](w3c/csswg-drafts#4874),
Firefox and Safari now need the `stroke-dasharray` values to use units,
so adding pixels.

Unfortunatelly, css variables don't work in animation `keyframes` on Safari
so don't have any other choice than make all the calculation in scss instead.
The `total-length` will have to be calculated separately and set staticaly.
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

9 participants