From 9eb7660478991f91e11b19c0f7f5ff9aa78778b7 Mon Sep 17 00:00:00 2001 From: Dmitry Kryaklin Date: Mon, 20 Jul 2026 18:41:36 +0300 Subject: [PATCH] fix: do not round non-zero values down to zero --- src/lib/serialize.js | 8 +++++++- test/index.js | 20 ++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/lib/serialize.js b/src/lib/serialize.js index 8e4844f..15f65ae 100644 --- a/src/lib/serialize.js +++ b/src/lib/serialize.js @@ -15,6 +15,8 @@ * @property {string} [calcName] Wrapper name to use when `calc()` is needed. Default `'calc'`. */ +const NOISE_FLOOR = 1e-12; + /** * @param {number} v * @param {number | false} prec @@ -25,7 +27,11 @@ function round(v, prec) { return v; } const m = Math.pow(10, prec); - return Math.round(v * m) / m; + const rounded = Math.round(v * m) / m; + if (rounded === 0 && Math.abs(v) > NOISE_FLOOR) { + return v < 0 ? -1 / m : 1 / m; + } + return rounded; } // §10.13 / §10.7.2: Infinity/NaN serialize as canonical keywords. diff --git a/test/index.js b/test/index.js index c165ae2..87a6f8b 100644 --- a/test/index.js +++ b/test/index.js @@ -382,6 +382,26 @@ test( testValue('calc(5/1000000)', '0.000005', { precision: 6 }) ); +test( + 'should not round a non-zero value down to zero', + testValue('calc(1/1000000)', '0.00001') +); + +test( + 'should not round a non-zero dimension down to zero', + testValue('calc(1px/1000000)', '0.00001px') +); + +test( + 'should not round a non-zero negative value down to zero', + testValue('calc(-1/1000000)', '-0.00001') +); + +test( + 'should keep rounding float noise to zero', + testValue('calc(0.1px + 0.2px - 0.3px)', '0px') +); + test( 'should reduce browser-prefixed calc (1)', testValue('-webkit-calc(1px + 1px)', '2px')