CSS计算-保留两位小数向下取整

52

我有以下情况:

div {
    width: calc((100% / 11) - 9.09px);
}
在这种情况下,100%等于1440px,而9.09px在Sass中通过数学计算生成。
结果为:94.55px,因为calc将其向上舍入,但我需要94.54px向下舍入)。
如何将其向下舍入到最接近的百分之一位?
编辑:示例

3
您不应该得到那两个值。(1440 / 11)= 130.90909px,减去9.09px = 121.89109px。请创建一个能够重现您错误的[MCVE],谢谢。 - TylerH
2
但是按照规范,CSS的calc()会向上取整。因此,如果您想要向下取整,您需要使用JavaScript。 - TylerH
@TylerH,现在问题主体中有示例。 - Cleiton Souza
7
W3C官方讨论 - "添加round()/floor()/ceil()函数" - 请点赞支持 - vsync
请翻译以下程序相关内容,从英语到中文。仅返回翻译后的文本:相关链接:https://dev59.com/PL3pa4cB1Zd3GeqPWAMQ - Temani Afif
6个回答

221

一般而言,我会说这是不可能的,但有一个黑客技巧。然而在网络上,黑客技巧似乎成为了常态,而非例外,所以我只能说这是可能的:

div {
    --shf: 4.9406564584124654e-322;
    width: calc(((100% / 11) - 9.09px) * var(--shf) / var(--shf));
}

这段代码的作用:将要四舍五入的数值乘以一个非常小的值,使其在第三个小数点后溢出。然后,它将截断的值除回去,得到数值的四舍五入版本。这种方法假定您支持的所有浏览器都使用64位浮点数值。如果不是这样的话,不仅会导致错误,而且在使用更小的浮点数据类型时可能会返回零,从而完全破坏您的页面。

将指数改为-323可在第一位小数点处进行四舍五入,将指数改为-324可在整数值处进行四舍五入。


11
出于好奇,你是怎么想到那个具体的数字作为“--shf”的参数的? - Daniel Einars
13
它是最小次正规化双精度浮点数的值(https://en.wikipedia.org/wiki/Double-precision_floating-point_format#Double-precision_examples)。 - Sean Anderson
1
你的点赞来自于 https://www.reddit.com/r/webdev/comments/k0yj3k/how_to_round_down_numbers_in_css/。 - user13634030
1
@PhilippWilhelm是个扫兴的人,让他自己想一会儿=P - GTCrais
1
@rexblack,从技术上讲,你可以;Floor(x) = Round(x - 0.5)Ceiling(x) = Round(x + 0.5) - Eliseo D'Annunzio
显示剩余4条评论

14

很遗憾,CSS中没有原生的方法来四舍五入(或向上/向下取整)数字。

不过,你提到你正在使用Sass。我找到了一个小型的Sass库,可以将数字四舍五入、向下取整或向上取整到指定的精度。

例如,如果你有一个数值为94.546,你可以使用decimal-floor(94.546, 2),它会返回94.54

不幸的是,如果你必须使用calc()在CSS中进行实时计算,这可能无法帮助你。但是,如果你可以预先计算width并通过Sass将其向下取整,那么就可以满足你的需求。一种可能的解决方案是使用@media查询作为设置断点的方式,并在Sass预处理中使用这些断点。


很遗憾,它并没有解决我的问题。非常感谢您的解释和建议。 - Cleiton Souza

4

round() CSS 函数

CSS Values and Units Module Level 4 中,您可以使用 round() CSS 函数 对数字或尺寸进行任意舍入。

round(<rounding-strategy>, valueToRound, roundingInterval)

可选的 rounding-strategy 可以是 up, down, nearest(默认值) 或者 to-zero,分别对应于 Javascript 中的 Math.ceil, Math.floor, Math.roundMath.trunc

示例

<canvas> 元素调整大小到与其父元素几乎相同(“舍入间隔为 a CSS pixel,而不是设备像素。”),保持画布像素宽高比为 1:1(假设 window.devicePixelRatio 是自然数):

canvas {
    display: block;
    width: round(down, 100%, 1px);
    height: round(down, 100%, 1px);
}

浏览器支持

目前只有 Safari 支持此功能。

另请参阅


0

如果你的问题是与一个像素舍入误差相关的视觉差异,那么在大多数情况下,你实际上不需要进行舍入。一个相对简单的解决方案是使其中一个项目占据所有剩余空间。

在弹性布局的情况下,如果你不需要布局换行,甚至可以选择其中一个中心项目,以获得最不明显的效果。

.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上下文中,如果您的目标只是使每个元素相等,则可能根本不需要计算。有关详细信息,请参见this question
在表格中,由于单元格宽度是从左到右计算的,因此可以采用类似的技巧,但必须将最后单元格的width: 100%设置为,因为没有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%;
}

0
如果您动态生成CSS,我创建了一个小类来执行简单的函数,如round(),ceil(),floor(),abs(),mod()和sign()--它可用于构建复杂的calc规则,您可以将其作为参数传递给其他人。如果您使用“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}) `);
    }
}

这里可能不太明显的是,您可以传递其他CSS变量等。因此,我使用观察器来监视对象的大小更改并设置自定义CSS变量。然后,我们可以使用这些自定义变量并将它们传递给这些函数,例如:$('#ID').css('width',cssHack.round(cssHack.toUnit(cssHack.floor("calc( var(--window-width,'1024') / 3)' ,'px)。所以当我的观察器或事件在body级别更改--window-width时,我的calc规则会立即应用,此时无需JavaScript。 - Joe Love

-1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接