我有以下情况:
div {
width: calc((100% / 11) - 9.09px);
}
在上下文中,
100%
= 1440px
,并且9.09px
是用sass在数学中生成的。
结果是:
94.55px
,因为calc
将其向上舍入,但我需要94.54px
(向下舍入)。
如何向下舍入到最接近的百位?
一般来说,我会说这是不可能的,但是有一个技巧。然而在网络中,黑客攻击似乎是常态,而不是例外,所以我只想说这是可能的:
div {
--shf: 4.9406564584124654e-322;
width: calc(((100% / 11) - 9.09px) * var(--shf) / var(--shf));
}
它的作用:它将要舍入的值乘以一个非常小的值,该值从小数点第三位开始下溢。然后,它将截断的值除以,得到该值的舍入版本。这假设您支持的所有浏览器都使用 64 位浮点值。如果不这样做,不仅这会是错误的,而且在使用较小的浮点数据类型时它可能会返回零,从而完全破坏您的页面。
将指数更改为 -323 以舍入第一个小数点,将指数更改为 -324 以舍入整数值。
不幸的是,CSS 中没有本地方法来对数字进行舍入(或向上/向下)。
但是 - 您提到您正在使用 Sass。我发现了一个小型 Sass 库,可以将数字舍入、下取整和向上取整到指定的精度。
例如,如果您有
94.546
,您可以使用 decimal-floor(94.546, 2)
,这将返回 94.54
。
不幸的是,如果您必须使用
calc()
来通过 CSS 进行动态计算,这可能没有帮助。但是,如果您可以预先计算 width
并使用 Sass 对其进行铺底,那么它将满足您的需求。一个可能的解决方案是使用 @media
查询作为设置断点并在 Sass 预处理中使用这些断点的方法。
round()
CSS 函数在 CSS 值和单位模块级别 4 中,您可以使用
round()
CSS 函数对数字或尺寸进行四舍五入。
round(<rounding-strategy>, valueToRound, roundingInterval)
可选的
rounding-strategy
可以是up
、down
、nearest
(默认)和to-zero
之一,分别对应Math.ceil
、Math.floor
、Math.round
和Math.trunc
在 JavaScript 中。
将
<canvas>
元素调整为 almost(“舍入间隔为 CSS 像素,而不是设备像素。”) 适合其父元素,保持画布像素长宽比为 1:1(假设window.devicePixelRatio
是自然数):
canvas {
display: block;
width: round(down, 100%, 1px);
height: round(down, 100%, 1px);
}
目前 Chrome、Safari 和 Firefox 支持此功能。
如果您的问题是与一像素舍入误差相关的视觉差异,则在大多数情况下,您实际上不需要舍入。一个相对简单的解决方案是让其中一个项目占据所有剩余空间。
在弹性场景中,如果您不需要布局换行,您甚至可以选择其中的一个中心项目,以获得尽可能不明显的效果。
.some-block {
width: calc( ( 100% / 11 ) - 9.09px );
flex-shrink: 0;
}
.some-block:nth-of-type(5) {
// Will attempt to take the whole width, but its siblings refuse to shrink, so it'll just take every bit of remaining space.
width: 100%;
}
根据您的具体 CSS 情况,可以通过使用填充或边距以及可能的附加嵌套元素来完全避免像素减法。这样,CSS
calc()
就变得无关紧要了,这一切都可以在 Sass 中完成,Sass 拥有更强大的数学工具,并且不会让客户端进行计算。
同样在 Flex 上下文中,如果您的目标只是使每个元素相等,则可能根本不需要计算。有关详细信息,请参阅此问题。
在表格中,由于单元格宽度是从左到右计算的,因此可以采用类似的技巧,但是您必须将
width: 100%
赋予 last 单元格,因为没有 flex-shrink
的概念,并且列宽是决定从左到右。
.my-table {
table-layout: fixed;
}
.table-cell {
width: calc( ( 100% / 11 ) - 9.09px );
}
.table-cell:last-of-type {
// Will attempt to take the whole width, but since previous column widths have already been determined, it cannot grow any further than its allocated width plus any stray pixels.
width: 100%;
}
如果您动态生成CSS,我创建了一个小类来执行简单的函数,如round()、ceil()、floor()、abs()、mod() 和sign()——它可以用于构建复杂的函数计算规则,您可以将其作为参数相互传递。如果使用“var(--my-variable)”作为参数,则将使用 CSS 变量。 注意:它最适合原始数字,并且有一个实用函数 toUnit 可以在最后转换为像素(等)。
可以这样调用,以jquery为例设置样式:
$('#my-element').css('width', `${cssHack.toUnit(cssHack.round(1000/3),'px')}`)
下面是该类的代码(es6,无依赖项):
class cssHack
{
//primary used for dynamic css variables-- pass in 'var(--dynamic-height)'
static toUnit(val,unit)
{
unit='1'+unit;
return ` calc(${val} * ${unit}) `;
}
static round(val)
{
// the magic number below is the lowest possible integer, causing a "underflow" that happily results in a rounding error we can use for purposeful rounding.
return ` calc(${val} * ${Number.MIN_VALUE} / ${Number.MIN_VALUE}) `;
}
static abs(val)
{
return ` max(${val}, calc(${val} * -1)) `;
}
static floor(val)
{
return cssHack.round(` calc(${val} - .5) `);
}
static ceil(val)
{
return cssHack.round( `calc(${val} + .5) `);
}
static sign(val)
{
let n = ` min(${val},0) `; //if val is positive then n =0. otherwise n=val.
let isNegative= ` min(${cssHack.ceil(cssHack.abs(n))},1) `;
let p = ` max(${val},0) `; //if val is negative then n=0, otherwise n = val;
let isPositive= ` min(${cssHack.ceil(cssHack.abs(p))},1) `;
return ` calc(${isPositive} + calc(${isNegative} * -1)) `;
}
static mod(val, base)
{
let abs = cssHack.abs(val);
let div = ` calc(${abs} / ${base})`;
let dec = ` calc(${div} - ${cssHack.floor(div)})`;
return cssHack.round(` calc(${dec} * ${base}) `);
}
}
你就不能用粗话来圆吗?既然你已经使用了它,请尝试它的 round、floor 和 ceil 方法: https://sass-lang.com/documentation/modules/math#bounding-functions
(也在旧版本的 sass 中,但语法不同)