-
Notifications
You must be signed in to change notification settings - Fork 661
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] Add spread()
to CSS
#8391
Comments
Values might contain commas themselves (note --multiple-items: (1; 2; 3; 4; 5);
--single-item: 6;
some-prop: random-item(--rnd1; spread(--multiple-items); var(--single-item)); |
spread()
to CSSspread()
to CSS
@Loirooriol Thanks! Yes, I mistakenly used I think a comma would be a reasonable default for most properties, and this spec could support other delimiters like the Example A: custom non-comma delimiter* {
--multiple-items: (1; 2; 3; 4; 5);
--single-item: 6;
some-prop: random-item(var(--ident); spread(--multiple-items, ';'); var(--multiple-items));
} Example B: delimiter conversion* {
--multiple-items: 1, 2, 3, 4, 5;
--single-item: 6;
some-prop: random-item(var(--ident); spread(--multiple-items, ',', ';'); var(--multiple-items));
} This way, any set of values stored in a variable can be used regardless of what delimiter is used in it, and then converted to match the format needed for its new context. |
I agree that there's a need for something in this vein, to allow storing arglists for functions like The core issue here is that a function can take So I think there are two possible approaches:
The two are basically identical in usage: .foo {
--multiple-items: spread(1; 2; 3; 4; 5);
--single-item: 6;
some-prop: random-item(--x; var(--multiple-items); var(--single-item));
/* equivalent to */
some-prop: random-item(--x; 1; 2; 3; 4; 5; 6);
}
/* and nesting them works */
.foo {
--some-items: spread(1; 2; 3);
--more-items: spread(var(--some-items); 4; 5; 6);
--some-prop: random-item(--x; var(--more-items));
} There are only meaningful difference between the two approaches is whether they're allowed in places that don't require them - |
@tabatkins Thanks for all the feedback! I agree, and either of those sounds good to me also. I'm still thinking about the pros and cons of each. With that model in mind, would CSS sets always work use a semicolon delimiter rather than another symbol? Also, would this be valid syntax, not including the .foo {
--some-items: (1; 2; 3);
--some-prop: random-item(--x; spread(var(--some-items)));
} If this wouldn't be considered valid syntax, it may be helpful to include some other function like That way, all of these would be valid: .foo {
--some-items: set(1; 2; 3);
/* spreading into `nth()` */
--first-item: nth(1; spread(--some-items));
/* spreading into `random-item()` */
--random-item: random-item(--x; spread(--some-items));
} I think it could be useful for I do wonder in regard to the delimiter if it would help to be able to spread into other properties using a different delimiter. For example: :root {
--colors: red, green, blue;
}
div {
--overlay-color: rgb(0 0 0 / 75%);
--overlay: linear-gradient(rgb(0 0 0 / 75%), rgb(0 0 0 / 75%));
background: var(--overlay), linear-gradient(var(--colors)); /* requires comma delimiter */
color: random-item(--x per-element; spread(--colors)); /* requires semicolon delimiter */
} Similar to how Maybe that's a possibility to consider later though. For starters, I think either of your proposed examples more than meets the use case I was aiming for with this proposal. Thanks! |
On second thought, I think the word
|
If we need to separate
Invalid under
Note that in either option, you only use (That is, we're not defining a higher-level concept of "a list of values", and then invoking it at the usage point to spread it into multiple args, like the JS
None of those examples need any help. All of them can be accomplished today using custom properties and (This does make me lean towards |
@tabatkins @Loirooriol It may even be worth including the functions
Also, relatedly, @Crissov had a pretty interesting proposal in a comment on the For the sake of continuity, let's call this function .foo {
--items: set(1; 2; 3);
/* spreading into dynamic `nth()` */
--random-item: nth(random --x per-element; spread(--items)); /* random becomes a keyword here rather than a dedicated `random-pick` function */
--first-item: nth(1; spread(--items));
--also-first-item: nth(first; spread(--items));
--last-item: nth(last; spread(--items));
--odd-items: nth(odd; spread(--items)); /* returns filtered list: list(1; 3) */
--even-items: nth(even; spread(--items)); /* returns filtered list: list(2) */
--range-of-items: nth(3 to 5; spread(--items)); /* returns filtered list: list(3) */
--two-and-down-items: nth(-n + 2; spread(--items)); /* returns filtered list: list(1; 2) */
--all-items: nth(n; spread(--items)); /* essentially copies the list, pointless but valid */
} |
Yeah, I could lean towards option 2 as well, though I think it would help to whitelist certain usages of If we were to introduce some kind of list/set function that actually houses lists of args and makes them reusable, then it may be worth discussing my other comment and how such a function could benefit all |
What are you imagining this would help with? When used directly in
There's no need for such a function; as long as your list isn't semicolon-separated, custom properties already hold "lists of args" just fine, and |
TL;DR: That makes sense. In fact, I think In that case, spread would only need to be used in variables as you suggested. Could we still interface other functions with it down the road like :root {
--colors: spread(blue; red);
}
main {
background: linear-gradient(
nth(first; var(--colors)),
nth(last; var(--colors))
);
} more exhaustive thoughts probably only half-worth even reading
I was thinking that if a list could be stored in a variable on its own without needing In other words, this would be valid: :root {
--colors: (blue; red); /* possibly wrapped by `list()` other something equivalent
}
main {
background: linear-gradient(
nth(first; spread(--colors)),
nth(last; spread(--colors))
);
color: random-item(--x; spread(--colors));
} ^ Example 1
I guess my thought here was that the general syntax for lists could be that of a semicolon-delimited list, which could be used in other functions like To that point, I think it boils down to whether there is ever a case we wouldn't want such a list to be spread. If the only value of a list is for its arguments/values to be later spread, then yes, I think either of your proposed options would work perfectly. In that case, we wouldn't need any sort of If that's the case, could we still interface other functions to be able to consume those arg lists? The :root {
--colors: spread(blue; red);
}
main {
background: linear-gradient(
nth(first; var(--colors)),
nth(last; var(--colors))
);
} |
Yes, (It'll also work anywhere else, for anything, it's just unnecessary in any other case.) |
Okay, awesome. I dig that, and it'll basically remove the need for any separate I'd love to move forward with the model from Would it possibly be worth also introducing a second function like Like this, for example: .foo {
--colors-rgb: spread(red; green; blue);
--colors-cmy: spread(cyan; magenta; yellow);
--random-item: random-item(color-single; random-item(color-group; unspread(--colors-rgb); unspread(--colors-cmy));
} In this example, the innermost nested I'm wondering if this holds any value— being able to pass a spread group as a group rather than its individual pieces in certain contexts, but if you think this would complicate things too much, I can understand and appreciate that viewpoint as well. Thanks. |
Making that sort of nesting work would require actually thinking about these values as a "list" structure rather than just a sequence of tokens. It's possible, but I question the need for it. ^_^ |
@tabatkins Fair enough — thanks! |
This |
Nah, they're pretty different.
|
They are similar in the sense that they wrap something inside a function, and then the value is unwrapped when using |
The execution ends up extremely different, is the thing - holding something for one substitution (or arbitrary substitutions until explicitly un-rawed), vs holding it for arbitrary substitutions until it hits a non-universal grammar. |
It's not a given that the executions need to be different. The original |
It's not; one of the use-cases that |
Yeah, so:
The difference is if you have a chain of custom properties referencing each other, and you want to unraw earlier. But |
Proposal
It would help to add support for a new
spread()
in CSS that would work identically tovar()
except that it would spread any chained values contained in the variable as if they had each been used individually.Syntax
The syntax would be something like this, expressed in JS/TS:
It could then be used in CSS like this:
Using
spread()
, the random value in the example above would have an equal chance of being any of the six values—1
2
3
4
5
6
Without
spread()
, the random value generated would only be one of two options—1, 2, 3, 4, 5
6
Alternative syntax
To keep this feature in line with others in CSS, I took a more functional approach using
spread()
, however, if we wanted to follow the trend of other languages, the traditional...
spread syntax could be employed, which would look like this:The text was updated successfully, but these errors were encountered: