css calc - округлить с двумя десятичными знаками
У меня следующая ситуация:
div {
width: calc((100% / 11) - 9.09px);
}
В контексте 100% = 1440px, и 9.09px генерируется в математике с sass.
Результат: 94.55px, потому что функция calc округляется в большую сторону, но мне нужно 94.54px (округляется в меньшую сторону).
Как я могу округлить до ближайшего сотого места?
# Редакция: пример.
6 ответов
В общем я бы сказал, что это невозможно, но есть взлом. Однако в сети хаки кажутся нормой, а не исключением, поэтому я просто скажу, что это возможно:
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.
Функция CSS
В CSS Values and Units Module Level 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>
элемента почти (интервал округления представляет собой пиксель CSS , а не пиксель устройства.) соответствует его родительскому элементу, сохраняя соотношение сторон пикселя холста 1:1 (при условии, чтоwindow.devicePixelRatio
является натуральным числом):
canvas {
display: block;
width: round(down, 100%, 1px);
height: round(down, 100%, 1px);
}
Поддержка браузера
В настоящее время это поддерживает только Safari .
Смотрите также
Если вы динамически генерируете свой 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}) `);
}
}
Если ваша проблема заключается в визуальном несоответствии, связанном с ошибкой округления в один пиксель, в большинстве случаев округлять не нужно. Относительно простое решение - сделать так, чтобы один из ваших предметов занимал все оставшееся место.
В гибком сценарии, если вам не нужно обертывать макет, вы даже можете выбрать один из центральных элементов для получения наименее заметного эффекта.
.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, который имеет гораздо более мощные математические инструменты и не заставляет клиента работать для вычислений.
Также в контексте гибкости, если ваша цель просто сделать все элементы равными, вам могут вообще не понадобиться вычисления. См. Этот вопрос для подробностей.
В таблице, поскольку ширина ячеек вычисляется слева направо, можно использовать аналогичный трюк, но вам придется указать
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%;
}
ты не можешь с дерзостью? поскольку вы уже используете его, попробуйте его методы round, floor и ceil:https://sass-lang.com/documentation/modules/math#bounding-functions
(также в более старых версиях sass, но с другим синтаксисом)