46

我有以下情况:

div {
    width: calc((100% / 11) - 9.09px);
}

在上下文中,100%=1440px9.09px是在数学中使用 sass 生成的。

结果是:94.55px,因为向上calc舍入,但我需要(向下舍)。94.54px

我怎样才能四舍五入到最接近的百分位?

编辑:示例

4

4 回答 4

203

一般来说,我会说这是不可能的,但有一个黑客。然而在网络中,黑客似乎是常态,而不是例外,所以我只想说这是可能的:

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

这是做什么的:它将要四舍五入的值乘以一个非常小的值,该值下溢从第三个小数点开始的值。然后,它将截断的值除回去,得到该值的四舍五入版本。这假定您支持的所有浏览器都使用 64 位浮点值。如果他们不这样做,这不仅会出错,而且在使用较小的浮点数据类型时它可能会返回零,从而完全破坏您的页面。

将指数更改为 -323 以在第一个小数点处舍入,将 -324 更改为以整数值舍入。

于 2020-11-19T23:22:59.337 回答
16

不幸的是,CSS 中没有一种原生方式来舍入(或 ceil/floor)数字。

然而——你提到你正在使用 Sass。我找到了一个小型 Sass 库,它可以将数字四舍五入、取整和取整到指定的精度。

例如,如果你有一个 had94.546你可以使用decimal-floor(94.546, 2)which 会返回94.54

calc()不幸的是,如果您必须使用CSS 进行动态计算,这可能无济于事。width但是,如果您可以使用 Sass预先计算并设置它,它将满足您的需求。一种可能的解决方案是使用@media查询作为设置断点的一种方式,并在 Sass 预处理中使用这些断点。

于 2016-06-10T19:12:38.687 回答
1

如果您的问题是一个像素舍入误差相关的视觉差异,在大多数情况下,您实际上不需要舍入。一个相对简单的解决方案是让您的一个项目占用所有剩余空间。

在 flex 场景中,如果你不需要你的布局来换行,你甚至可以选择你的中心项目,以获得尽可能不明显的效果。

.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 案例,可以通过使用填充或边距以及额外的嵌套元素来完全避免像素减法。这样,CSScalc()就变得无关紧要了,这一切都可以在 Sass 中完成,Sass 具有更强大的数学工具,并且不会让客户端进行计算。

同样在 flex 上下文中,如果您的目标只是使每个元素相等,则可能根本不需要计算。有关详细信息,请参阅此问题

在表格中,由于单元格宽度是从左到右计算的,因此可以使用类似的技巧,但是您必须给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%;
}
于 2020-12-01T16:06:40.427 回答
1

如果你动态生成 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}) `);
    }
}
于 2021-11-11T18:09:13.567 回答