Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[css-values-5] Introduce nth-item() #11103

Open
tabatkins opened this issue Oct 28, 2024 · 4 comments
Open

[css-values-5] Introduce nth-item() #11103

tabatkins opened this issue Oct 28, 2024 · 4 comments

Comments

@tabatkins
Copy link
Member

tabatkins commented Oct 28, 2024

Back in #5009 (comment) I summarized the various "conditional" things we might want to add. We've now added the if() function, and the big one left from that summary list is nth-item() (called nth-value() in that comment, but we should be consistent with random-item()'s naming).

This is a fairly trivial addition functionality-wise, and it has two good arguments for including it:

  1. As argued in the thread, it gives a complementary syntax for conditionals, letting you centralize the actual condition to one spot on your page and just use it to set an integer that'll select things from the list. That way, you don't have to repeat your conditions all over your page if you have a lot of things that'll use the same set of tests.
  2. If you can do random-item() to select a random item from a list, surely you should be able to do nth-item() to select a non-random item from a list, that's just something authors will expect. ^_^

Syntax would just be:

nth-item( <integer> , [ <declaration-value>? ]# )

And it'll select the nth argument according to the first argument, yielding the guaranteed-invalid value if the index goes past the end of the list.

Maybe the first arg can have an optional clamp keyword, which would make the index clamp to the largest valid index instead of being invalid, so authors can use the final argument as the "default" value.

@Crissov
Copy link
Contributor

Crissov commented Oct 29, 2024

Would negative indices count from the end of the list? What would index 0 return then?

I’ve expressed a preference for a unified select by index function before. I’m still in favor of it, but overall it’s just syntax details.

select( random | <integer> , [ <declaration-value>? ]# )

If this also supported select by key, we’d basically have a switch construct without fallthrough behavior.

select( random | <integer> | <string> , [ [<string> :]? <declaration-value>? ]# )

@tabatkins
Copy link
Member Author

Since other indexed things in CSS (grid lines, notably) allow counting from the end with negative values, presumably we'd do the same. 0 would just be invalid (or clamped to 1, if we add the clamp option).

Selecting by random requires the fuller handling of random caching that random-item() provides. In theory it's possible to merge in the grammar, but in practice it would be more trouble than it's worth.

Selecting by key should be handleable by if(), with a touch more verbosity (you'd repeat the var() in each branch). If that ends up being too verbose because you're doing it a lot, nth-item() is already the intended way to fix that (use an if() to select an integer in one place, then use the integer to index a bunch of lists).

@LeaVerou
Copy link
Member

I think I would prefer decoupling the list specification from the list operations, so we can have a dedicated <list> type, which would allow us to accept lists as values to custom properties, or even regular properties. Ideally with a modifier, e.g. <list[number]>.

There are many, many use cases around lists and scales, e.g.:

  1. Getting the nth item
  2. Getting the N%th item (e.g. the midpoint)
  3. Getting the closest item to a given value (rounding up/down/closest)
  4. Getting the item N places before/after the closest item
  5. Generating a scale via interpolation or a mix of fixed points and interpolated points.

All of the above have several use cases around design tokens/design systems. Tackling 1 first is ok, but we should have a plan for the others down the line.

It may also be worth thinking how lists of dimensions fit in to lists of colors (see #10034) or other types of values.

@tabatkins
Copy link
Member Author

@LeaVerou I don't think I agree, at least not without a lot more support for list handling. None of the things you described appear to be doable in CSS even with a list type; they all require looping, variable assignment, etc. We'd have to introduce more functions to represent these operations.

And if we did introduce these additional functions, they don't, as far as I can tell, require any special "list" type; they can all be handled just fine by the existing infrastructure of "lists" being a convention for comma-separated items. Custom functions can take lists as an argument without any additional input from us (the caller would just wrap the list in {}, and the function can either splat it into another function directly or wrap it in more {} to re-group it if needed). Built-in functions haven't yet needed to worry about expressing lists as anything other than an n-ary set of arguments, but if we ever do, the same {} syntax works.

@astearns astearns moved this to FTF agenda items in CSSWG January 2025 meeting Jan 22, 2025
@astearns astearns moved this from FTF agenda items to Regular agenda items in CSSWG January 2025 meeting Jan 22, 2025
@astearns astearns moved this from Regular agenda items to Friday morning in CSSWG January 2025 meeting Jan 28, 2025
@astearns astearns moved this from Friday morning to Friday afternoon in CSSWG January 2025 meeting Jan 31, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Friday afternoon
Development

No branches or pull requests

4 participants