Csswg-drafts: [css-values] Add sign() math function

Created on 15 Jan 2020  路  4Comments  路  Source: w3c/csswg-drafts

Can we add the analogous of the ECMAScript Math.sign()? That is

  • sign(x) is 1 if x > +0
  • sign(+0) is +0
  • sign(-0) is -0
  • sign(x) is -1 if x < -0
  • sign(NaN) is NaN

For non-zero values it can be achieved with x / hypot(x) or clamp(-1, x / 0, 1), but these are NaN for zero.

I think sign() can be very useful given that CSS doesn't have conditionals (#3455).

For example:

width: calc(if (100vw > 100px) then (1em) else (1lh));

is not possible, but with sign() I could use

--cond: sign(max((100vw - 100px) / 1px, 0));
width: calc(1em * var(--cond) + 1lh * (1 - var(--cond)));

Or #2513 is discussing a round() function that rounds to the nearest, or upwards in case of tie. So round(2.5) would be 3 and round(-2.5) would be -2. But what if in case of tie I want to round towards 0, or away from zero? It's very simple with sign():

round(-hypot(x)) * sign(-x) /* round towards 0 in case of tie */
round(hypot(x)) * sign(x) /* round away from 0 in case of tie */
Needs Testcase (WPT) css-values-4

Most helpful comment

While I have no direct objection to a sign() function, I'd much rather address your particular use cases directly, with rounding options and with conditional functions.

All 4 comments

While I have no direct objection to a sign() function, I'd much rather address your particular use cases directly, with rounding options and with conditional functions.

But conditional functions were rejected in #3455 because they are too powerful. With sign() we can have some kind of conditions but it's just arithmetic so it's fine.

And about rounding options, it was just an example, but there are many others.
For example, in case of tie maybe someone wants to choose the nearest even number, e.g. 6.5 rounds to 6 and 7.5 rounds to 8 (a bit strange but some language does this by default if I recall correctly).

So my point is that native CSS can't offer all possible behavior customizations, because there are so many options. Instead we should let authors achieve what they want with sign(), and if some behavior is very popular but not much readable with sign(), then add a nicer way in CSS.

The example could be

--is-tie: calc((1 - hypot(sign(2*x - ceil(x) - floor(x)))) * sign(ceil(x) - floor(x)));
calc(round(x/2)*2 * var(--is-tie) + round(x) * (1 - var(--is-tie)));

The CSS Working Group just discussed sign(), and agreed to the following:

  • RESOLVED: add the sign() function as described in the issue, restricted to numbers only

The full IRC log of that discussion
<bkardell_> topic: sign()

<bkardell_> TabAtkins: this one was opened by oriol, asking for Math.sign equivalent, the usecase presented is hacky, but sure, why not - it seems unobjectionable - I'm happy to add it... he notes you can actualy implement it yourself, it is even worse

<astearns> github: https://github.com/w3c/csswg-drafts/issues/4673

<bkardell_> myles_: should the sign of 1px be....

<bkardell_> heycam: it should return a number if we allow lengths

<bkardell_> emilio: what about percentages?

<bkardell_> TabAtkins: 50% should resolve to whatever that resolves to

<bkardell_> bkardell_: in ..pixels

<bkardell_> TabAtkins: in many cases, pixels, but whatever that resolves against

<heycam> make calc(sign(1px)) == 1, because you usually use the result of sign() to multiply against other things

<bkardell_> myles: you could always add non-numbers later

<bkardell_> heycam: does css really support positive and negative values?

<dbaron> s/values/zeroes/

<Rossen___> q?

<bkardell_> TabAtkins: in calc, yes - we use the js semantics -- once you exit the calc no... it can affect the infinity

<dbaron> TabAtkins: yes, but only inside of calc()

<bkardell_> fantasai: I dont think you can parse one in?

<bkardell_> dbaron: you can write an negative 0, but it is just 0

<bkardell_> TabAtkins: if you produce a negative 0 as a result of the calc, you can have a negative 0

<bkardell_> Rossen___: is there a use case for that?

<bkardell_> TabAtkins: consistency with JavaScript?

<bkardell_> Rossen___: so we _want_ that in this case? :)

<bkardell_> TabAtkins: you can insert directly via typed om, actually

<bkardell_> TabAtkins: anyone have an objection to sign() restricted to numbers only?

<bkardell_> Rossen___: any objections?

<astearns> cbiesinger: Tab explained you get negative zero by dividing by negative infinity, which you get by -1/0

<bkardell_> RESOLVED: add the sign() function as described in the issue, restricted to numbers only

Added sign() in 8e3fb63a.

Was this page helpful?
0 / 5 - 0 ratings