Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is a `calc()` width with an illegal value not ignored?

Tags:

css

css-calc

Inspired by this question, I found this interesting phenomenon.

Since negative widths are illegal, and therefore should be ignored, I would expect style properties like width:-200px; and width:calc(0% - 200px); to have no effect. And indeed, for the first one it doesn't. The second one, however, is not ignored: a width of 0 is used instead.

See this example:

div {border:1px solid; background:lime;}

#badwidth {width:-200px;}

#badcalc {width:calc(0% - 200px);}
Div with bad width:
<div id="badwidth"> </div>

Div with bad calc:
<div id="badcalc"> </div>

If the width property was ignored, the div would be its full width (like the top one). However, it is collapsed to 0 (see the black line to the left; that's the border).

For reference, here are some other divs, to demonstrate 1) that calc(0% - 200px) by itself is not an error, and 2) that they work fine and the first snippet is an anomaly.

div {border:1px solid; background:lime;}

#calc {margin-right:calc(0% - 200px);}
Plain div:
<div> </div>

With calc(0% - 200px) in a place where it's OK:
<div id="calc"> </div>

So, why do normal widths and calculated widths behave differently?
If it was just one browser, I'd call it a bug. But they all treat this the same way! So there must be something I'm overlooking. What?

like image 449
Mr Lister Avatar asked Feb 02 '17 12:02

Mr Lister


1 Answers

The evaluation of calc and the allowed values in a rule are different, as you are experiencing. According to the spec CSS Values and Units:

While some properties allow negative length values, this may complicate the formatting and there may be implementation-specific limits. If a negative length value is allowed but cannot be supported, it must be converted to the nearest value that can be supported.

In this case, -200 is rounded up to 0 as it is the closest value supported for width.

Edit

The section before also states:

Properties may restrict the length value to some range. If the value is outside the allowed range, the declaration is invalid and must be ignored.

When declaring width: -200px, this value is outside of the acceptable range, and is thus ignored. However, it seems calc evaluates -200 before the check occurs, and rounds it up to be within the acceptable range, so it is not ignored.

Update

Thanks to @CBroe for the reference to the spec on calc:

Parse-time range-checking of values is not performed within calc(), and therefore out-of-range values do not cause the declaration to become invalid. However, the used value resulting from an expression must be clamped to the range allowed in the target context.

Since widths smaller than 0px are not allowed, these three declarations are equivalent:

width: calc(5px - 10px);
width: calc(-5px);
width: 0px;

Note however that width: -5px is not equivalent to width: calc(-5px)! Out-of-range values outside calc() are synactically invalid, and cause the entire declaration to be dropped.

like image 199
chazsolo Avatar answered Nov 07 '22 06:11

chazsolo