Re: [csswg-drafts] [css-values] Add round()/floor()/ceil() functions (#2513)

> If there are two units, then use the first unit, so that round(2cm + 19px) is the same as round(2cm + 19px, 1cm). This would just be, what do you call it, syntax sugar? But it sure would make it simpler to read and author.

It's actually not, and for some very important reasons.

First and most importantly, *the precision you want to round to is virtually never "1 of the unit I'm using"*.  Obviously there's no need to write `round(2.4cm)` - you can just write `2cm` in your stylesheet and be clearer. If you're passing in a value from a variable, like `round(var(--foo))`, you don't know the unit and can't hand-round it, but then you're getting an unpredictable precision, thus an unpredictable effect on your layout, which is almost certainly not what you want. This is because the point of rounding is to make something a multiple of *some base length that's significant to your exact situation*.  JS's "round to nearest integer" isn't even that useful actually; I'm pretty sure *most* of my rounding usage in JS looks like `Math.round(val / step) * step`; I only use an un-scaled `round()` when I'm displaying a value on-screen (and even then, I often use `.toFixed()` on the value, which takes a decimal precision).

Second, if there are multiple values, relying on the first one is a footgun. A seemingly-harmless change, like switching from `calc(2cm + 5em)` to `calc(5px + 2cm + em)`, completely changes the result; if it was written as `calc(2cm + 5em, 1cm)`, then changing the value has no such unpredictability.

Third, tracking the types means being aware of exact parsed syntax in a way that no other math function (or anything else in CSS, for that matter) is. In every single other instance, `1em`, `16px`,`12pt`, etc are all exactly equivalent. Breaking that correspondence is something we should do only with a very good reason.

And even if we did do so, it would just introduce further confusion - %s are processed late, and are *explicitly* about their resolved value elsewhere in math functions. (`sign()` has an explicit callout about the fact that `sign(50%)` might return -1!) And then what about a function? Or an attr() with the unit specified by the keyword? Etc.

The best we could reasonably do for a default precision is to base it on the canonical unit for a given type - round to the nearest px for all lengths, etc. But that's even further removed from any hope of matching the author's intent, per my first point.

Syntax sugar is great when it simplifies a common case, and improves overall readability by removing obvious details. It's bad when it causes more special cases you have to worry about.

>  Which is also why I favor multiple functions instead of extra parameters.

As your examples show, it's literally just a matter of placing the keyword before or after the `(`; there is no other change beyond which punctuation you use to separate it from the surrounding syntax. Preferring one vs the other is a reasonable aesthetic preference, but we need more than that to decide (after all, I personally prefer the consistent look of the common function name + keyword).

We went for the keyword for two reasons: first, as dbaron stated (hopefully captured in the minutes?), there are actually more rounding modes than this, particularly "round to nearest, but resolves ties by X" (instead of always resolving a tie as "up"), and keywords are compatible with adding such control later; second, just in case this is something that an author or library wants to make controllable, a keyword can be controlled via a variable, but part of a function name can't be. (In JS it can, but we don't offer that sort of concatenation and indirection in CSS.)

> I don’t really follow what mod() or rem() are (I guess mod() means modulo?), or when you need them. The abbreviations tend to obscure their meaning.

Some variety of modulus operator is common to virtually every programming language in existence. `mod` and `rem` are very common names for them, as the Wikipedia list shows; the only other common name is `%`, which I think you'll agree obscures even more. ^_^ I do explain what the abbreviated names mean in the spec (which I finished on the plane and just now pushed), and how to think about their behavior and their differences.

If you don't know when you'll use mod, that's fine, you don't need it then. But, as the existence of the terrible abuse-the-precision-range-of-doubles hack linked on Twitter shows, people do want mod functionality.

-- 
GitHub Notification of comment by tabatkins
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/2513#issuecomment-578563444 using your GitHub account

Received on Monday, 27 January 2020 01:10:52 UTC