What is the biggest usable number for use in calc() in CSS?
Asked Answered
C

2

5

The title says it all.

I want to know, which is the biggest number I can use in CSS inside a calc() arithmetic.
Is it the same as the biggest number in JavaScript?

When I try this with transform the limit seems to be 1e39 (in Chrome and for transform: translateX())

div span {
  display: block;
  width: 100px;
  height: 100px;
  background-color: gold;
}
div:nth-child(1) span {
  -webkit-transform: translatex(calc(1e38px * 1e-37));
          transform: translatex(calc(1e38px * 1e-37));
}
div:nth-child(2) span {
  -webkit-transform: translatex(calc(1e39px * 1e-37));
          transform: translatex(calc(1e39px * 1e-37));
}
div:nth-child(3) span {
  -webkit-transform: translatex(calc(1e40px * 1e-37));
          transform: translatex(calc(1e40px * 1e-37));
}
<div>
   <code>transform: translatex(calc(1e38px * 1e-37));</code>
  <span></span>
</div>

<div>
   <code>transform: translatex(calc(1e39px * 1e-37));</code>
  <span></span>
</div>

<div>
   <code>transform: translatex(calc(1e40px * 1e-37));</code>
  <span></span>
</div>

The specification for CSS Values and Units Module Level 3 says this in the paragraph 4.1 Range Restrictions and Range Definition Notation

Properties can restrict numeric values to some range. If the value is outside the allowed range, then unless otherwise specified, the declaration is invalid and must be ignored. Range restrictions can be annotated in the numeric type notation using CSS bracketed range notation—[min,max]—within the angle brackets, after the identifying keyword, indicating a closed range between (and including) min and max. For example, <integer [0,10]> indicates an integer between 0 and 10, inclusive.

Note: CSS values generally do not allow open ranges; thus only square-bracket notation is used.

CSS theoretically supports infinite precision and infinite ranges for all value types; however in reality implementations have finite capacity. UAs should support reasonably useful ranges and precisions. Range extremes that are ideally unlimited are indicated using ∞ or −∞ as appropriate. For example, <length [0,∞]> indicates a non-negative length.

If no range is indicated, either by using the bracketed range notation or in the property description, then [−∞,∞] is assumed.

Note: At the time of writing, the bracketed range notation is new; thus in most CSS specifications any range limitations are described only in prose. (For example, “Negative values are not allowed” or “Negative values are invalid” indicate a [0,∞] range.) This does not make them any less binding.

So it seems as if the properties themselves should define the range of possible values. In this light, which is the biggest possible number in any property. Is there a list of the properties somewhere that I can look into for this? This will also depend on browser vendors as I understand.

You may ask why I want to know this?

I want to have a kind of Heaviside function in CSS which should work as a switch with resulting values 0 or 1 depending on the value of the input being bigger or smaller than a threshold with the help of CSS function clamp()

--switch: clamp(0, (50.000001 - var(--input)) * 1e10, 1);

This will result in var(--switch) being 0, if var(--input) is smaller than 50, and 1, if bigger than 50 (and 1 half if exactly 50.000001).

Edit

Another example: The switch calculation from above could be used for a range calculation like this When I use a value of 1e36 it works in Firefox, but not 1e37

.container {
  display: -webkit-box;
  display: flex;
}

.box {
  --switch1: clamp(0, (var(--value) - 59.0000001) * 1e36, 1);
  --switch2: clamp(0, (91.0000001 - var(--value)) * 1e36, 1);
  --range-switch: clamp(0, var(--switch1) * var(--switch2), 1);
  width: 50px;
  height: 50px;
  box-sizing: border-box;
  background-color: gold;
  border: 1px solid;
  -webkit-transform: translateY(calc(15px - var(--range-switch) * 15px));
          transform: translateY(calc(15px - var(--range-switch) * 15px));
  background-color: hsl(calc(100 * var(--range-switch)), 100%, 50%);
  display: -webkit-box;
  display: flex;
  text-align: center;
  -webkit-box-align: center;
          align-items: center;
  -webkit-box-pack: center;
          justify-content: center;
}
<h1>Range switch (CSS only)</h1>
<div class="container">
  <div class="box" style="--value: 50">50</div>
  <div class="box" style="--value: 60">60</div>
  <div class="box" style="--value: 70">70</div>
  <div class="box" style="--value: 80">80</div>
  <div class="box" style="--value: 90">90</div>
  <div class="box" style="--value: 100">100</div>
</div>
Cathryncathy answered 31/8, 2020 at 8:33 Comment(5)
To be clear, you are looking for the MAX_SAFE_INTEGER equivalent? Because calc(1e999 - 1e-999 + 20) is correctly computed as 20, but calc(1e999 * 1e-999 + 20) will be 20 in Chrome instead of 21 (and a weird 3.40282e+38 in FF...), so we can assume that these numbers are still used, even though the result is not what would be expected.Clepsydra
@Clepsydra In theory yes. But in practice, the value will be not defined anywhere, but will be dependent on the browser/platform and on the CSS property. See the last example I added to my OPCathryncathy
I'm not saying it is the same as js MAX_SAFE_INTEGER (it clearly isn't and as you mentioned it's not even the same per browser), but an "equivalent". I'm just pointing out that it's not MAX_VALUE, where values higher would be treated as Infinity, since some arithmetic seems to still work even with values that should be Infinity. (And I'm not saying I have an answer either).Clepsydra
I am probably missing something but why you need the big number? if you want to simulate the range doing the following: jsfiddle.net/hva374yk/1 would be enough. Only the sign is needed: If negative, it will fall into 0 and if positive it will fall into 1 (considering the fact that you are dealing with integer)Disarming
@TemaniAfif, Look at this fiddle: jsfiddle.net/HerrSerker/5j27k6p0/1. 59.5 will not give the expected result. With the high number it work as intended: jsfiddle.net/HerrSerker/5j27k6p0/2Cathryncathy
D
4

I would consider a different idea where you don't need to use huge number.

I will use the formula max(x - MIN , 1/(x - MIN))

if x > MIN the result will be positive (>0) and the max will for sure be bigger than 1 (a * 1/a = 1 so one term is bigger than 1 or both equal to 1) so the result will be clamped to 1

if x < MIN the result will be negative (<0) and clamped to 0.

The only drawback with this method is that the formula is undefined for x = MIN so consider a non conventional value for MIN (hard to be picked by the user)

.container {
  display: -webkit-box;
  display: flex;
}

.box {
  --switch1: clamp(0, max(var(--value) - 59.9987 , 1/(var(--value) - 59.9987)), 1);
  --switch2: clamp(0, max(90.0011 - var(--value),  1/(90.0011 - var(--value))), 1);
  --range-switch: clamp(0, var(--switch1) * var(--switch2), 1);
  height: 50px;
  padding:0 8px;
  box-sizing: border-box;
  border: 1px solid;
  transform: translateY(calc(15px - var(--range-switch) * 15px));
  background-color: hsl(calc(100 * var(--range-switch)), 100%, 50%);
  display: flex;
  align-items: center;
  justify-content: center;
}
.box::before {
  content:attr(style);
  font-family:monospace;
  text-indent:-9ch;
  overflow:hidden;
  font-size:18px
}
<h1>Range switch (CSS only)</h1>
<div class="container">
  <div class="box" style="--value: 50"></div>
  <div class="box" style="--value: 59"></div>
  <div class="box" style="--value: 59.5"></div>
  <div class="box" style="--value: 59.98"></div>
  <div class="box" style="--value: 60"></div>
  <div class="box" style="--value: 61"></div>
  <div class="box" style="--value: 70"></div>
  <div class="box" style="--value: 80"></div>
  <div class="box" style="--value: 89.8"></div>
  <div class="box" style="--value: 90"></div>
  <div class="box" style="--value: 90.99"></div>
  <div class="box" style="--value: 91"></div>
  <div class="box" style="--value: 100"></div>
</div>
Disarming answered 31/8, 2020 at 14:15 Comment(5)
I have seen a similar approach in a request for CSS sign(). But I was not convinced. Your's is better. But it doesn't really answer my question, but only helps with the motivation. It might come up in a different context again.Cathryncathy
@Cathryncathy I don't think we can give an accurate answer to your initial question since (as you have noticed) each browser behave differently. We can only try to find different ideas based on the use casesDisarming
You might be true. But I'm reluctant to check your answer as the correct one. I upvoted it thoughCathryncathy
@Cathryncathy no need to check it, it"s still too early ;) more users will probably come with different answers and probably more accurate ones.Disarming
There won't be many with a more proficient CSS expertise than yoursCathryncathy
D
1

If you still want to use a big number you can rely on infinity which is a new value introduced in CSS Values Level 4.

The browser support is still not good. You can test the below using Chrome

.container {
  display: flex;
}

.box {
  --switch1: clamp(0, (var(--value) - 59.0000001) * infinity, 1);
  --switch2: clamp(0, (91.0000001 - var(--value)) * infinity, 1);
  --range-switch: clamp(0, var(--switch1) * var(--switch2), 1);
  width: 50px;
  height: 50px;
  box-sizing: border-box;
  background-color: gold;
  border: 1px solid;
  transform: translateY(calc(15px - var(--range-switch) * 15px));
  background-color: hsl(calc(100 * var(--range-switch)), 100%, 50%);
  display: flex;
  text-align: center;
  align-items: center;
  justify-content: center;
}
<h1>Range switch (CSS only)</h1>
<div class="container">
  <div class="box" style="--value: 50">50</div>
  <div class="box" style="--value: 60">60</div>
  <div class="box" style="--value: 70">70</div>
  <div class="box" style="--value: 80">80</div>
  <div class="box" style="--value: 90">90</div>
  <div class="box" style="--value: 100">100</div>
</div>
Disarming answered 29/4, 2023 at 10:16 Comment(1)
Strange how MDN list Firefox as compatible but Chrome not: developer.mozilla.org/en-US/docs/Web/CSS/calc-constantCathryncathy

© 2022 - 2024 — McMap. All rights reserved.