I have the following situation:
div {
width: calc((100% / 11) - 9.09px);
}
In the context, 100%
= 1440px
, and <
In general I would say that it's not possible, but there's a hack. However in the web, hacks seem to be the norm, instead of the exception, so I'll just say that it is possible:
div {
--shf: 4.9406564584124654e-322;
width: calc(((100% / 11) - 9.09px) * var(--shf) / var(--shf));
}
What this does: it multiplies the value to be rounded by a really small value that underflows the value starting at the third decimal point. Then, it divides the truncated value back, resulting in a rounded version of the value. This assumes that all browsers you support use 64-bit floating point values. If they don't, not only this will be wrong, it might return zero when using smaller floating point data types, completely breaking your page.
Change the exponent to -323 to round at the first decimal point and -324 to round at integer values.
Unfortunately, there is not a native way in CSS to round (or ceil/floor) numbers.
However — you mentioned you are using Sass. I found a small Sass library that can round, floor, and ceil numbers to a specified precision.
For example, if you had a had 94.546
you could use decimal-floor(94.546, 2)
which would return 94.54
.
Unfortunately, this might not help if you have to use calc()
to calculate on the fly with CSS. However, if you can pre-calculate the width
and floor it with Sass it would fit your needs. A possible solution could be using @media
queries as a way to set breakpoints and use those breakpoints in your Sass preprocessing.
If your problem is a one-pixel rounding error related visual discrepancy, in most cases, you don't actually need to round. A relatively simple solution is to make one of your items take up all of the remaining space.
In a flex scenario, if you don't need your layout to wrap, you can even pick oen of your center items for the least noticeable effect possible.
.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%;
}
Depending on your exact CSS case, the pixel substraction could potentially be avoided altogether by using paddings or margins and maybe an additional nested element. That way, the CSS calc()
becomes irrelevant and it all could be done in Sass, which has much more powerful math tools and doesn't make the client work for calculations.
Also in a flex context, if your goal is just to make every element equal, you may not need calculations at all. See this question for details.
In a table, since cell widths are calculated left to right, a similar trick can be employed, but you'll have to give width: 100%
to the last cell, since there's no concept of flex-shrink
and column widths are decided left to right.
.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%;
}