so tab today

@tabatkins
326 Followers
34 Following
60 Posts

was @tabatkins on Twitter, now am @tabatkins.com on BlueSky. Only on Masto rarely.

editor of many CSS specs; lover of games, kpop, and animals; promoter of base-6 as optimal human-oriented number base

Pronounsthey
Homepagehttps://tabatkins.com
BlueSkyhttps://bsky.app/profile/tabatkins.com
@JaneOri The weird exception is "normal" CSS functions, which have an... interesting relationship with the concept of "arguments". In general, the grammar of a CSS function is the same level of looseness and customization that property grammars are; "arguments" are a construct we lean on only when it's useful.

@JaneOri [...] which is that a `var(--foo)` call, particularly when nested into a function call like `--bar(1, var(--foo), 3)`, *looks* identical to `bar(1, foo, 3)` in JS or similar languages. There, you know for a fact that the foo variable, whatever its value is, fills exactly the second argument and no more.

If you want more, you write `bar(1, ...foo, 3)`, making it explicit. That's exactly what the CSS functions are doing; direct knowledge transfer across web languages.

@JaneOri There have been counter-arguments; you just disagree with them.

The issue is arbitrary-substitution functions in general. We need to be able to tell where the argument boundaries are, so we can do things like not evaluating `var()` fallback unless needed, or short-circuiting in `if()`, etc. Spreading is a special case there.

There's also a more direct DX argument for it [...]

@JaneOri I think you have overargued yourself into confusion here. While the slightly different syntax behavior isn't ideal, I believe it's far less of a problem or confusion than you're implying here. In general it's meant to Just Work without having to think too hard about it. (500 char comment blocks aren't the best for talking about this, tho.)
@JaneOri The fact that the value is used as-as is, in fact, the point. I'm not certain why you think it would be useless? It's exactly as useful to take a font list as a single font.
@JaneOri It was definitealy not a "last minute" call. It was the result of a bunch of discussion, some on the list and a bunch internal, about how unused `if()` arguments (and unused fallbacks in several other arb-sub funcs) should behave. Without this behavior, there are reasonable `if()` functions you would be unable to write, as they'd be cyclic even though every possible branch, on its own, wasn't; meanwhile a similar `@container` would work fine, just be verbose.
@JaneOri Right, outside of arb-sub functions, we just treat property values (including any functions) as being opaque token streams separated by arb-sub functions. The arb-sub substitutes in, and only after that do we care about any parsing.

@JaneOri Purely as an author-expectation language design issue, I think there's reasonable arguments both ways.

I came down in favor of the behavior split so we *could* do short-circuiting. There's a more ideal CSS where this is more consistent across the board, but we work with what we've got.

@JaneOri For example, say you're going to use the second argument for a `font-family` value. You might *expect* people to just pass a single family name, but it would also be reasonable to pass a comma-separated fallback list. If you didn't anticipate that, your function would break; now, it works automatically.

@JaneOri The *secondary* benefit of it is predictability. When you write `--my-func(1, var(--arg), 3)`, you very likely expect the arg to set the second argument. But in the earlier pre-spread version, it `--arg` contains commas, it would set *multiple* arguments. You could defensively wrap it like `--my-func(1, {var(--arg)}, 3)`, but we don't expect people to remember to do that.

The new spread behavior makes it work as we think people will expect, by default.