为啥不忽略具有非法值的 `calc()` 宽度?
Posted
技术标签:
【中文标题】为啥不忽略具有非法值的 `calc()` 宽度?【英文标题】:Why is a `calc()` width with an illegal value not ignored?为什么不忽略具有非法值的 `calc()` 宽度? 【发布时间】:2017-06-19 12:39:40 【问题描述】:受this question的启发,我发现了这个有趣的现象。
由于负宽度是非法的,因此应该被忽略,我希望像 width:-200px;
和 width:calc(0% - 200px);
这样的样式属性没有效果。事实上,对于第一个它没有。然而,第二个并没有被忽略:而是使用 0 的宽度。
看这个例子:
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>
如果 width 属性被忽略,则 div 将是其全宽(如顶部)。但是,它被折叠为 0(见左边的黑线;那是边界)。
作为参考,这里有一些其他 div,以证明 1) calc(0% - 200px)
本身不是错误,2) 它们工作正常,第一个 sn-p 是异常。
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>
那么,为什么正常宽度和计算宽度的行为不同? 如果它只是一个浏览器,我会称之为错误。但他们都以同样的方式对待这个!所以一定有我忽略的东西。什么?
【问题讨论】:
我几乎不将此行为视为错误或异常:我希望width: calc(100% - 500px)
在 500px 及以下处导致宽度为 0;如果宽度回到默认值auto
0 到 499 像素之间,我会很生气! :-) 以您的0%
为例,我们人类知道它永远不会产生正值,所以是的,它看起来是一种奇怪 行为,但恕我直言,其他示例则不然。 CSS WG 和浏览器供应商必须处理许多情况
【参考方案1】:
正如您所经历的那样,计算的评估和规则中的允许值是不同的。根据规范CSS Values and Units:
虽然某些属性允许负长度值,但这可能会使格式复杂化,并且可能存在特定于实现的限制。如果允许但不支持负长度值,则必须将其转换为可以支持的最接近的值。
在这种情况下,-200
向上舍入为 0
,因为它是宽度支持的最接近的值。
编辑
前面的部分还指出:
属性可能会将长度值限制在某个范围内。如果值超出允许范围,则声明无效,必须忽略。
在声明width: -200px
时,此值超出可接受范围,因此被忽略。但是,calc
似乎在检查发生之前评估 -200 ,并将其四舍五入到可接受的范围内,因此不会被忽略。
更新
感谢@CBroe 提供reference to the spec on calc:
值的解析时范围检查不在 calc() 中执行,因此超出范围的值不会导致声明无效。但是,表达式产生的使用值必须限制在目标上下文允许的范围内。
由于不允许小于 0px 的宽度,这三个声明是等价的:
width: calc(5px - 10px);
width: calc(-5px);
width: 0px;
但是请注意,width:-5px 不等于 width:calc(-5px)! calc() 之外的超出范围的值在语法上是无效的,并导致整个声明被删除。
【讨论】:
如果适用,width:-200px
的值也会向上舍入为 0。但是,正如您在第一个示例中看到的那样,它不是。
查看我的编辑 - calc
必须先评估,然后才能传递最终值,以根据属性规则进行检查。
“如果适用,width:-200px 的值也将四舍五入为 0” – 不,因为 width 是一个不允许负值的属性首先 - 所以从一开始,第一个引用的句子就不适用于宽度:“虽然某些属性允许负长度值,[...]”
对于 calc 然而,这里明确指定它必须如何处理超出范围的值,drafts.csswg.org/css-values-3/#calc-range:“解析时间范围检查不在 calc( ),因此超出范围的值不会导致声明无效。但是,从表达式产生的使用值必须限制在目标上下文允许的范围内” - 这就是这里发生的事情。 calc 给出了一个否定的结果,但是对于不允许的宽度 - 所以结果值被“钳制”到 0。
@CBroe 哇。请您将其发布为答案吗?以上是关于为啥不忽略具有非法值的 `calc()` 宽度?的主要内容,如果未能解决你的问题,请参考以下文章
Angular2:如何使用具有某些组件值的 css calc()?