- From: Tab Atkins Jr. via GitHub <noreply@w3.org>
- Date: Tue, 03 Mar 2026 03:09:21 +0000
- To: public-css-archive@w3.org
So, summarizing this for the purpose of the breakout. Reminder that we define how and when "random" values are shared by reference to a *caching key* - if two instances of a function have the same key, they'll have the same "base value" (a random 0-1 number that is then scaled to the requested range); otherwise they'll have different base values. To make it concrete, imagine one hundred elements all styled with the following:
```css
.box {
width: random(..., 100px, 200px);
height: random(..., 100px, 200px);
border: thin solid;
}
```
# Current Spec
The caching key is a 2-tuple of `(property+index, element)`. ("index" distinguishes between multiple random()s in a single property - the first is index 0, the second is 1, etc). (Ignore the "document" part of the caching key in the spec, it's not relevant for this discussion.)
Grammar is `[ <dashed-ident> || element-shared ]?`.
* `random(100px, 200px)` is "most random" - (almost) every instance of it across elements and styles will resolve differently. (It gets a property/index/element identifier in its caching key, so virtually all instances are unique). All 100 elements will be unique random rectangles.
* `random(element-shared, 100px, 200px)` is "less random" in that it causes instances *across elements* to be shared. (It nulls out the "element" identifier in the caching key, so two elements using the function in the same property in the same way will share a key.) When used in different ways, they'll still be different. All 100 elements will be the *same* random rectangle.
* `random(--foo, 100px, 200px)` is "less random" in that it causes instances *across properties* to be shared. (It replaces the property/index identifier in the caching key with the given dashed-ident, so using the same ident in two properties will share a key on a single element.) When used on different elements, they'll still be different. All 100 elements will be unique random *squares*.
* `random(--foo element-shared, 100px, 200px)` is the "least random" - it combines both of the above effects. Every single instance resolves identically, in all properties and on every element in the page. All 100 elements will be the same random square.
This design first ensures that the simplest usage (no first argument) is maximally random, probably what people want by default. Then, adding values in the first argument always make it "less random", so the syntax develops in a consistent direction.
The downsides (raised by Bramus) are two-fold, and both based on observing people's intuitions about the function in practice. The first is that people commonly misread "element-shared" to mean a value shared *within* an element, rather than *between* elements. That is, they expect `width: random(element-shared, ...); height: random(element-shared, ...);` to resolve to the same value on a single element. The second is that they expect a dashed-ident, on its own, to already be "least random", because they feel like they're "naming" the value, so it should be the same every time they reuse the name. They're surprised when instead it still generates unique values across elements.
# Proposal
The caching key is a 4-tuple of `(name, property, index, element)`.
Grammar is `[ <<dashed-ident>> [ element || property ]? ]?`.
* `random(100px, 200px)` is identical to current spec, "most random". (Caching key has an index, property, and element; name is null.) All 100 elements are unique random rectangles.
* `random(--foo, 100px, 200px)` is "least random". You've given this random value a name, and every instance will get the same value. (Caching key has its name set, but all other elements are null.) All 100 elements are *identical* random *squares*.
* `random(--foo element, 100px, 200px)` is "somewhat more random" in one possible way - it's a named value, but with the element ID "mixed in" to the name, so all instances on a single element are identical, but across different elements are different. (Caching key sets its name and element, nulls the property and index.) The 100 elements are unique random *squares*.
* `random(--foo property, 100px, 200px)` is "somewhat more random" in another possible way - it's a named value, but with the property name "mixed in" to the name, so all instances in a given property are the same across the stylesheet, but across different properties are different. (Caching key sets its name and property, nulls the element and index.) The 100 elements are *identical* random rectangles.
* `random(--foo element property, 100px, 200px)` is "somewhat more random" in both ways, mixing in both the property name *and* the element ID into the name (but still nulling the index). This is *very similar* to specifying nothing at all (`random(100px, 200px)`) except with you setting the name instead of the UA automatically setting an index. Potentially useful for complicated values (`matrix()`? Multiple background layers?) where you want to be specific about what's shared and what's not in a single property, but otherwise get max randomness.
This design similar starts from the default (no first argument) being "most random", as people still expect that by default. It then makes naming the value "least random", better matching author intuition. You can opt into intermediate states with additional keywords, where the keywords represent additional dynamically-determined elements of the "name" that make things "more random".
## Index?
Currently, the index is automatically wiped when you specify any part of the caching key, so `margin: random(--foo property, 10px, 20px) random(--foo property, 10px, 20px);` sets both vertical and horizontal margins to the same random value. I think this is probably still the right behavior by default, as it keeps things consistent across the values, but it means you do have to *manually* re-add the index into the name if you want it to matter, like `margin: random(--foo-0 property, 10px, 20px) random(--foo-1 property, 10px, 20px);`. Trivial, but does require manual numbering, which has caused issues in other properties when people start abstracting. Possibly we can also add an `index` keyword to allow the index to be auto-mixed-in to the name as well.
On the other hand, using `index` by itself is a little weird; while it will cause instances in a single property to be unique, it'll (perhaps unexpectedly) share between values in different properties that happen to be at the same index. If you want that sort of cross-property coordination, it's *probably* best to use an explicit name. So possibly `index` has to be paired with `property`.
I suggest we *accept* this, pairing it with `property`, changing that segment of the grammar to `element || [ property | property-index ]`.
## Omit the name?
This design differs slightly from up-thread, in that if you're specifying anything at all, you need to specify the name. This isn't strictly necessary for the design; it could be reasonable to, say, just allow `random(element, 100px, 200px)`, which'll still share the value within the element. It's identical to just using the exact same name on all instances. Similarly, `random(property, 10px, 20px)` would reuse the random value across all instances of that property, as if you'd just specified the same name everywhere.
However, I think the mental simplicity of "always specify a name, then mix in additional dynamic things" is worth the cost of authors perhaps having to write an otherwise-useless dashed-ident in. (And remember that `--` is a perfectly valid dashed ident, so `random(-- element, ...)` is always possible if you really want to minimize extra typing).
I suggest we *reject* this, keeping the static part of the name required if you're doing anything fancy at all. But I'd be fine if the WG disagreed with me, and wanted to allow *any* portion of the name to be specified or omitted.
--
GitHub Notification of comment by tabatkins
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/13132#issuecomment-3988334064 using your GitHub account
--
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config
Received on Tuesday, 3 March 2026 03:09:22 UTC