Open Bug 1298537 Opened 4 years ago Updated 2 years ago

calc(): + and - with one operand of unitless length 0 and another of a length with explicit units are incorrectly ignored as invalid

Categories

(Core :: CSS Parsing and Computation, defect, P3)

50 Branch
defect

Tracking

()

People

(Reporter: bicknellr, Unassigned)

References

(Depends on 1 open bug, )

Details

User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36

Steps to reproduce:

Write a CSS rule using `calc()` to produce a length and add unitless zero to that length within the `calc()`. For example, `calc(1px + 0)`.


Actual results:

The rule is considered invalid.

Here's a repro: http://jsbin.com/jejewa/1/edit?html,output


Expected results:

The rule should be valid. One specific place this bug causes a problem is when using `calc()` with CSS custom properties. If you write a `calc()` function using a custom property as an operand to an addition or subtraction with a length, the person setting the value of that custom property you've provided can't use the unitless zero shorthand even though it is a valid length.
Status: UNCONFIRMED → RESOLVED
Closed: 4 years ago
Resolution: --- → DUPLICATE
Duplicate of bug: 1264520
Just as an update, this behavior has been deemed correct by the spec author. I'm not sure I'd really consider it a duplicate of the other bug, but it should stay closed either way.
Bug 1264520 is about properties which support both number and length should accept both in one calc, while this bug seems to be about the unitless zero should be recognized as 0px even for length-only properties. So I wouldn't consider this as a duplicate as that bug.

A fix of that bug may make it easier to fix this bug, and vice versa.
Status: RESOLVED → REOPENED
Ever confirmed: true
Resolution: DUPLICATE → ---
https://drafts.csswg.org/css-values/#calc-type-checking says:

> At + or -, check that both sides have the same type, or that one side is a <number> and the other is an <integer>. If both sides are the same type, resolve to that type. If one side is a <number> and the other is an <integer>, resolve to <number>.
...
> If an operator does not pass the above checks, the expression is invalid.


So this is the expected behavior.
Status: REOPENED → RESOLVED
Closed: 4 years ago4 years ago
Resolution: --- → INVALID
But 0 is a valid <length>.

https://drafts.csswg.org/css-values/#lengths says:
> However, for zero lengths the unit identifier is optional (i.e. can be syntactically represented as the <number> 0).
Status: RESOLVED → REOPENED
Resolution: INVALID → ---
Status: REOPENED → NEW
Depends on: 1264520
Priority: -- → P3
I just ran into this as well while using the following technique to handle safe area insets:

:root {
	--safe-area-inset-top: 0;
	--safe-area-inset-bottom: 0;
	--safe-area-inset-left: 0;
	--safe-area-inset-right: 0;
}

/* iOS < 11.2 */
@supports (padding-top: constant(safe-area-inset-top)) {
	
	:root {
		--safe-area-inset-top: constant(safe-area-inset-top);
		--safe-area-inset-bottom: constant(safe-area-inset-bottom);
		--safe-area-inset-left: constant(safe-area-inset-left);
		--safe-area-inset-right: constant(safe-area-inset-right);
	}

}

/* iOS > 11.2 */
@supports (padding-top: env(safe-area-inset-top)) {
	
	:root {
		--safe-area-inset-top: env(safe-area-inset-top);
		--safe-area-inset-bottom: env(safe-area-inset-bottom);
		--safe-area-inset-left: env(safe-area-inset-left);
		--safe-area-inset-right: env(safe-area-inset-right);
	}
	
}

This all came crashing down in Firefox when I tried to use these safe area inset variables in calc() until I changed them all from 0 to 0px.  All of the above works fine in Safari and Chrome.

This bug will become more and more of an issue as more devices are released that need CSS similar to this.
Bug 1462233 is about to land though ;)
(In reply to Emilio Cobos Álvarez (:emilio) from comment #8)
> Bug 1462233 is about to land though ;)

That might fix this one particular case (since the safe area insets are being hard coded as 0px and not just 0), but that doesn't account for future env() values, nor does it solve the problem with other cases where there are perfectly valid use cases for putting 0 in calc().
(In reply to Justin Michael from comment #9)
> (In reply to Emilio Cobos Álvarez (:emilio) from comment #8)
> > Bug 1462233 is about to land though ;)
> 
> That might fix this one particular case (since the safe area insets are
> being hard coded as 0px and not just 0), but that doesn't account for future
> env() values, nor does it solve the problem with other cases where there are
> perfectly valid use cases for putting 0 in calc().

That's fair :)

FWIW, the code in comment 7 should probably use the fallback value for the env function, which is what I assume is supposed to be used for that. So should be something like:

  --safe-area-inset-top: env(safe-area-inset-top, 0px);
  /* .. */
I'd note that other browsers still behave like us here, and the spec still doesn't look so clear to me.

https://drafts.csswg.org/css-values/#calc-type-checking says:

> Anything else is a terminal value, whose type is determined based on its CSS type:
>
> <number>
> <integer>
>    the type is «[ ]» (empty map)
> <length>
>    the type is «[ "length" → 1 ]»

It's not clear where that CSS type comes from.

Let's say we parse "0" as a <length>, then that implies that "50px * 0" now becomes invalid. That's clearly bogus.
(In reply to Emilio Cobos Álvarez (:emilio) from comment #11)
> Let's say we parse "0" as a <length>, then that implies that "50px * 0" now
> becomes invalid. That's clearly bogus.

Oh, it can even be trickier for multiply indeed. Consider how would something like "0 * 0" works at all :)

It definitely needs clarification from the spec, I think.
You need to log in before you can comment on or make changes to this bug.