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:
1px) because the expression doesn't parse (Firefox doesn't propagate this quirk into calc()).0px.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
cc @smfr too :)
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.
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.
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.
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.
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:
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.
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.
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.
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!
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:
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.
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/
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 pixelsRESOLVED: This resolution does not apply to any quirks inside of calcRESOLVED: encourage SVG to follow this approachThe full IRC log of that discussion
<dael> Topic: [css-values] Quirky lengths and math expressions
<dael> github: https://github.com/w3c/csswg-drafts/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
Most helpful comment
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.