- From: Roman Komarov via GitHub <sysbot+gh@w3.org>
- Date: Tue, 22 Oct 2024 08:01:10 +0000
- To: public-css-archive@w3.org
kizu has just created a new issue for https://github.com/w3c/csswg-drafts: == [css-values] Proposal: `round()` to a finite scale == ## Background This is a proposal that I briefly discussed with @fantasai at CSWG F2F in A Coruña this year. The problem it tries to solve came up when I was writing [my latest article](https://kizu.dev/tree-counting-and-random/), so I finally found time to write it. One of the motivations for this proposal is a problem that was, for example, mentioned by @matthiasott in [his talk at CSS Day 2024](https://youtu.be/su6WA0kUUJE?feature=shared&t=2371) (a bit after 39:31), where he argues that using container query units for fluid type, while possible, leads to too many font-sizes on the page, making it not possible to create a harmonic type scale. But what if we could augment the existing `round()` to help with this and other similar cases? ## Proposal The current syntax of `round()` is `round(<rounding-strategy>?, A, B?)` where `A` and `B` are calculations that must share a type and resolve to any can resolve to any `<number>`, `<dimension>`, or `<percentage>`. My proposal is to change it to `round(<rounding-strategy>?, A, B*)` — use [`*`](https://www.w3.org/TR/css-values-4/#mult-zero-plus) instead of [`?`](https://www.w3.org/TR/css-values-4/#mult-opt) for the last argument. When only one value is provided as `B`, `round()` will work the same as now. When _multiple_ values are provided to `B`, the values would be treated as a _scale_ of the only values that the `A` should be rounded to. These values must be the only possible outcomes of the `round()` function: this is **not** rounding the value to either of the values in the regular sense, but using the provided values as a finite _scale_. If we were to think of a single B, it would represent an _infinite linear scale_, for example the default `1` argument there represents an infinite `1 2 3 4 N` scale, but if we'd want to round to a _finite_ scale, for example, to find _the closest prime number_ to a certain list of them, we could do ```CSS round(var(--foo), 1 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101); ``` This way, if we'd provide `--foo: 10`, it will round to the closest prime, resulting in `11`. And if we will provide something that is equally close to two values, like `--foo: 6`, then the `<rounding-strategy>?` will come into play: we could choose how exactly we'd want to handle cases like it — round things to the closest, or ceil/floor it. Implementation-wise, this should not be too complex: something like a binary search of the first argument with the provided list could be good enough. ## Other use-cases Aside from the typographic scale and choosing the closest prime number, I remember stumbling upon many different use cases. One prominent one: regular spacing scale. Various design systems can have a scale like `2px 4px 8px 12px 16px 20px 24px 32px 48px` for spacing, and similar to the Matthias's case with fluid typography, it would be great to evaluate some container query length units to the closest value from such a scale. There were other cases I encountered, but at the moment of writing this proposal I don't remember them: will update if I'll stumble upon them later, and if anyone had them as well — drop them in the comments, I'll update the proposal with them as well. ## Current Workaround Today, the simplest way we can attempt to approach this with the current CSS is by using a rather complicated complex conditional calculation which I described in my article. For the above list of primes (with some lower ones removed), it looks like this: ```CSS --limit: 102; --closest-prime: calc( var(--limit) - max( min(1, 11 - var(--x)) * (var(--limit) - 11), min(1, 13 - var(--x)) * (var(--limit) - 13), min(1, 17 - var(--x)) * (var(--limit) - 17), min(1, 19 - var(--x)) * (var(--limit) - 19), min(1, 23 - var(--x)) * (var(--limit) - 23), min(1, 29 - var(--x)) * (var(--limit) - 29), min(1, 31 - var(--x)) * (var(--limit) - 31), min(1, 37 - var(--x)) * (var(--limit) - 37), min(1, 41 - var(--x)) * (var(--limit) - 41), min(1, 43 - var(--x)) * (var(--limit) - 43), min(1, 47 - var(--x)) * (var(--limit) - 47), min(1, 53 - var(--x)) * (var(--limit) - 53), min(1, 59 - var(--x)) * (var(--limit) - 59), min(1, 61 - var(--x)) * (var(--limit) - 61), min(1, 67 - var(--x)) * (var(--limit) - 67), min(1, 71 - var(--x)) * (var(--limit) - 71), min(1, 73 - var(--x)) * (var(--limit) - 73), min(1, 79 - var(--x)) * (var(--limit) - 79), min(1, 83 - var(--x)) * (var(--limit) - 83), min(1, 89 - var(--x)) * (var(--limit) - 89), min(1, 97 - var(--x)) * (var(--limit) - 97), min(1, 101 - var(--x)) * (var(--limit) - 101) ) ); ``` This works! But this is not something that is easy to write or maintain by hand. ## Alternatives Considered Initially, I was thinking about either introducing a new function, or looking if we could somehow do this with `clamp()`. For some reason, I was not thinking about `round()` as a possible alternative, as I was stuck with it rounding to an _infinite_ scale. But `clamp()` works very differently from `round()`, where it _keeps_ the original value if it fits into the provided range. But we're really _rounding_ it to a scale, and it was @fantasai that proposed to think about just augmenting `round()`. ## Out of Scope I think there is something about being able to specify an alternative, non-linear _infinite_ list, maybe in a form of an equation similar to the one in the nth-child, but maybe a bit more complex. It would be great to be able to round something to a scale like 2 4 8 16 32 64 etc, or be able to specify a fallback if the value falls outside of the chosen _finite_ scale. In the future, I think these would be nice to have, but I'd propose to have separate issues discussing them and bikeshedding their syntax. A finite scale is a common enough case, and seems to be simple enough to implement, that I'd want us to first focus on it. Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/11067 using your GitHub account -- Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config
Received on Tuesday, 22 October 2024 08:01:11 UTC