The creator of the TV present The Good Place wrote a tie-in e-book about ethical philosophy which features a chapter known as “The Luck of the Draw,” discussing how the delusion of meritocracy leads folks to “underestimate the position that luck has performed of their lives.” Given how God appears to play cube with the universe, there’s something compelling in the best way artwork imitates life when web sites embrace managed chaos of their designs. The jury is out on whether or not excessive variations of this nondeterminism comparable to generative UI are a useful utilization of unpredictable UX. Certainly, after I see the YouTube feedback reacting to Google’s upcoming utilization of GenUI in search, perhaps it’s taking the thought too far down a nasty path. However there may be nonetheless one thing concerning the thought of a webpage that exists in a state of refined flux every time you land on it, the identical approach you may’t step into the identical river twice.
Actual-world use circumstances for randomness
I’m a guide who usually works on short-term, greenfield initiatives, which offer me with a window into the zeitgeist and the developments corporations assume are the longer term. It’s no coincidence that the thought of randomness permeated considered one of my latest initiatives. That’s epitomized by a burst of confetti to present the person a way of pleasure once they run a random draw they configured. And like many a UI function within the company world, the straightforward thought of confetti was topic to a number of revisions to make each randomized particle align with the consumer’s model.
In actual fact, the necessities turned customized sufficient that we ended up ditching the JavaScript plugin we have been utilizing and rolled our personal confetti implementation! This illustrates the stress between the conflicting wants for chaos and management in UX, even in a enjoyable function like random confetti.
Wouldn’t or not it’s good if we might wield managed presentational randomness within the presentation layer with out leaving CSS?
The CSS random() operate emerges
If unpredictable person experiences are having a second, it follows that CSS will do its half to make randomized layouts straightforward to implement. The creators of CSS have at all times been on a mission to reap widespread UI patterns into declarative CSS requirements. Consistent with that spirit, we see that in late 2025, Safari turned the primary browser to assist the CSS random() spec, as a part of an replace that emphasised “letting you clear up widespread use circumstances with HTML and CSS alone, paving the cowpaths, and decreasing the necessity for JavaScript or third-party frameworks.”
Since then, cool demos and discussions of random() hold popping up. As an illustration, Schalk Neethling confirmed us how CSS random() can provide us fine-grained management over the notorious confetti impact, and Alvaro Montoro made a powerful argument that CSS seems to be probably the most appropriate language for such duties. He factors out this strategy is according to the Rule of Least Energy, which inspires “fixing an issue utilizing the least highly effective language able to expressing and fixing it.”
Now the dangerous information: half a yr after Safari launched CSS random(), there isn’t readability on when it is going to land within the different browsers. At time of writing, there are indicators of life that each Chrome and Firefox have been engaged on it, however no ensures about when we will use it outdoors of the Apple world, even behind a browser flag.
So, it appears at present I can solely attempt the web demos of CSS random() on my work MacBook and never on my PC the place I do my private initiatives. I’m tempted to put in writing my very own implementation, however the syntax is surprisingly intricate, largely due to elaborate random caching and keying semantics, mixed with the choices for base values and intervals. Even when I might handle to get all these particulars appropriate, CSS random() is a part of an editor’s draft spec that’s within the “early exploration section” and “main breaking modifications are anticipated.”
On prime of that, from my dive into CSS polyfills in my article on ::nth-letter, we all know the entire thought of a CSS polyfill generally is a minefield.
With all these obstacles in thoughts, an individual must be a particular breed of loopy to try to polyfill CSS random().
Let’s polyfill CSS random()
One of many commenters on a neat YouTube demo of the function marvelled that it’s a “function that works ONLY IN SAFARI?!? Did the Earth get flipped the other way up?” Certainly, I’m extra accustomed to getting my first alternative to expertise emergent options in Chrome, which means my mates on iPhones usually can’t run my experiments.
And but, within the case of random(), it’s darkly poetic {that a} function based mostly on likelihood seems in an surprising place the place many people can’t use it. In actual fact, even Safari customers might profit from my css-random-polyfill bundle, as a result of Safari updates are tied to the OS, that means not everybody can improve to the newest model of the browser. Apart from, we all know how a lot Apple loves it whenever you hack their stuff to enhance compatibility.
Jokes apart, Apple appears severe concerning the “hackability” and transparency of the whole lot concerning the open supply WebKit engine that powers Safari, and a lot of the demos I’ve used to check my polyfill are forks of demos from the WebKit weblog, wherein the Apple Safari crew confirmed off the probabilities for CSS random() again when it was in Safari preview.
Demo: Random starfield
Right here’s my cross-browser model of the primary demo from the Safari crew’s article. It’s a randomly scattered subject of stars fading out and in at random intervals. The bigger, four-pointed stars all tilt on the similar randomly chosen angle. All stars have refined, randomly hued shadows round them.
Emigrate the Safari-only unique to a model that works in Chrome and Firefox, we have to change the HTML to reference my polyfill script and add the randomized marker class to all components that we need to polyfill.
As for the CSS, in contrast to my :nth-letter polyfill which makes use of a nonstandard selector that needs to be translated into legitimate CSS at runtime — and introduces drawbacks within the course of — this time we have to assist a brand new operate in CSS as an alternative of a brand new selector. It seems the CSS we will use on this state of affairs is technically legitimate, even in browsers which have by no means heard of CSS random(). Extra in a while why it's legitimate, however for now, simply discover that wherever we would like a random worth, we retailer it in an intermediate customized property, and we at all times should observe the conference that the property title begins with the prefix --random.
.star {
--random-star-size: random(1px, 7px, 1px);
background-color: white;
border-radius: 50%;
aspect-ratio: 1/1;
width: var(--random-star-size);
place: mounted;
--random-top: random(0%, 100%);
--random-left: random(0%, 100%);
prime: var(--random-top);
left: var(--random-left);
--random-hue: random(0, 360);
filter: drop-shadow(0px 0px calc(var(--random-star-size) * 0.7) oklch(0.7 0.2 var(--random-hue)))
drop-shadow(0px 0px calc(var(--random-star-size) * 3) white);
mix-blend-mode: hard-light;
--random-speed: random(2s, 5s);
animation: fade-in var(--random-speed);
animation-iteration-count: infinite;
--random-delay: random(2s, 5s);
animation-delay: var(--random-delay);
animation-direction: regular;
}
This starfield demo showcases a couple of totally different variations of the supported random() syntax, comparable to the optionally available third argument for specifying a step interval which, on this case, is used to randomly choose solely complete quantity values inside the vary:
--random-star-size: random(1px, 7px, 1px);
…and the element-shared base worth, which we use right here to tilt each four-pointed star by the identical randomly chosen angle.
.star.fourpointed {
--random-rotation: random(element-shared, -45deg, 45deg);
rotate: var(--random-rotation);
}
Be aware: Within the unique starfield demo, a lot of the random values have been used inline, which is admittedly extra elegant. The spec that features random() makes it clear that this sort of operate “can be utilized instead of any a part of any property’s worth,” similar to calc() or min(). So, by requiring additional ceremony and conventions, the polyfill is supporting a subset of what we are going to get with native random(). To see the glass half-full, it means the CSS stays appropriate with the native implementation: we might delete the script reference to the polyfill as soon as native assist goes baseline and our code will nonetheless work, prefer it does as we speak when it detects native assist in Safari. on this case the polyfill doesn't course of random() calls in any respect and it lets Safari do all of the work. This can be a compromise I can reside with, particularly if the choice is to press our noses in opposition to the glass of Safari-only demos on YouTube and make feedback comparable to one viewer did: “Can’t wait to make use of this in prod in 4 years.”
Demo: Random Coloured Grid Cells
Chris Coyier mentioned of the unique starfield demo from Apple that he discovered it “fairly darn compelling!” I agree, and after I was testing my polyfill, that demo was enjoyable to look at randomly twinkling, refresh and see the celebs scatter in another way utilizing an emergent, declarative CSS normal. Against this, I can’t say I've ever sat round wishing I might create a 100×100 CSS grid with randomly multicolored cells, so this instance from the Safari crew feels a bit like a contrived excuse to randomize one thing. Nevertheless, it did assist me check the polyfill assist of some totally different variations of the syntax.
The polyfill permits for some versatile syntax. You possibly can see that references to customized properties handed to the random() operate get substituted as anticipated, and you'll see that inlining a number of random() calls in the identical worth works. For instance, we will create a grid-area shorthand property worth with randomized row-start and column-start values.
.rectangle {
--random-grid-area: random(1, var(--rows), 1) / random(1, var(--columns), 1);
grid-area: var(--random-grid-area);
}
Demo: Wheel of fortune
This instance is from Tim Nguyen from the Safari crew. To proceed the themes of likelihood and synchronicity, I’ll point out that I had the great fortune to fulfill Tim final yr after I spoke at Net Instructions 2025. My discuss got here proper after his discuss, and now that I’m forking his CSS random() demo to create a cross-browser model, he's as soon as once more a troublesome act to observe.
You possibly can see on this instance that the ultimate random place of the wheel makes use of a distinct unit for its step interval parameter than for the minimal and most parameters.
@keyframes spin {
from {
rotate: 0deg;
}
to {
rotate: var(--random-rotation);
}
}
#wheel {
--random-rotation: random(2turn, 10turn, 20deg);
}
The combo of varieties is supported as a result of the specs say the values should be “resolvable to the identical knowledge kind,” so we're in a position to combine models so long as they're in the identical “general knowledge kind,” comparable to flip and deg, acquainted from the best way CSS calc() provides values with totally different models when it is smart, utilizing CSS typed arithmetic.
Be aware: To make the demo work with the polyfill, I needed to outline the variable in a CSS class that shall be utilized when the polyfill first hundreds, in distinction to Tim’s unique demo which makes use of the random() operate inside a keyframes animation that was utilized based mostly on a checkbox hack. That’s as a result of, for now, the polyfill solely processes the computed kinds which are utilized to components when the web page first hundreds. Since all my assessments move with this implementation, I'm leaving it like that for now within the curiosity of doing the only factor that would presumably work. There are methods we might discover to make the polyfill react to dynamic modifications to the computed kinds and/or the DOM.
Demo: Random squares
Chris Coyier has a knack for writing code that’s both as difficult or so simple as wanted to get his level throughout, and his CodePen “Very fundamental random() in CSS” is perhaps the only demo of CSS random() doable, displaying three randomly positioned squares with random colours. Under is my cross-browser model, which I additionally modified to randomize the scale of the squares, as a check that my polyfill helps random worth sharing utilizing customized keys.
Right here is the code I added to make every sq. have a random peak that is the same as its random width:
--random-height: random(--side, 40px, 100px);
--random-width: random(--side, 40px, 100px);
width: var(--random-height);
peak: var(--random-width);
This reassures that we're supporting the right syntax. Admittedly, customized keys shall be extra helpful in the true native model, which gained’t want the intermediate variables. Since we're utilizing intermediate customized properties, we might simply have used one customized property named --side and referenced that for each the peak and width values.
Chromium-only bonus demo: Simulate random-item utilizing a customized CSS operate
Lots of the above demos embrace random colours. That’s achieved by passing random numeric values into CSS shade capabilities comparable to rgb() or lch(). But when we had a listing of particular colours we wished to randomly select from, we will’t do this simply, which is why the spec for the CSS values and models module mentions the random-item() operate, though no browser at present implements it (aside from experimental assist in safari preview). If we had this operate, we might choose a random shade or anything from an arbitrary checklist of values:
random-item(element-shared, purple, blue, inexperienced);
The random-item operate takes a compulsory first argument of the kind random-caching-options, the identical as CSS random(), however then it takes a variable size checklist of arguments to randomly choose from, relatively than a minimal and most worth.
I don’t really feel like complicating the polyfill to assist a CSS syntax that isn’t carried out in any browser — evidently I solely give myself permission to do this annually. However now that we have now a model of CSS random() in Chromium which additionally helps CSS customized capabilities and inline conditionals, it’s exhausting to withstand seeing what occurs if we mix all these strange issues into one experiment. It seems these options collectively can get us fairly darn near the performance we’d get from random-item().
--random-index: random(element-shared, 1, 5, 1);
--random-color: --item(var(--random-index), aqua, purple, pink, gray, inexperienced);
Should you’re utilizing a Chromium-based browser, you may see the code in motion on this model of the squares demo which units all three components to the identical shade randomly chosen from the checklist.
The implementation of my generic --item customized CSS operate takes an --index argument adopted by 10 optionally available arguments. These may very well be elevated to any variety of arguments you assume would be the reasonable most dimension of a set you would want. Every of the optionally available arguments is made optionally available by defaulting it to an empty worth, so the caller of the operate solely must move within the arguments it must index. Lastly, the operate maps the --index to the argument at that index, as a result of CSS customized capabilities don't assist variable size collections of arguments the best way JavaScript capabilities do.
@operate --item(--index,
--arg-1: ,
--arg-2: ,
--arg-3: ,
--arg-4: ,
--arg-5: ,
--arg-6: ,
--arg-7: ,
--arg-8: ,
--arg-9: ,
--arg-10: ) {
outcome: if(
type(--index: 1): var(--arg-1);
type(--index: 2): var(--arg-2);
type(--index: 3): var(--arg-3);
type(--index: 4): var(--arg-4);
type(--index: 5): var(--arg-5);
type(--index: 6): var(--arg-6);
type(--index: 7): var(--arg-7);
type(--index: 8): var(--arg-8);
type(--index: 9): var(--arg-9);
else: var(--arg-10);
);
}
Sidenote: This generic helper operate is fascinating, as a result of Temani Afif has demonstrated cool use circumstances for with the ability to select from a listing of colours utilizing an --index variable, however the resolution he created was particular to the colour knowledge kind and he freely admits it’s “extra of a hack than a CSS function. So, use it cautiously.” Against this, the customized operate strategy will work with a listing of any knowledge kind, and I wouldn’t describe it as a hack as a result of it’s utilizing CSS requirements as meant, albeit emergent requirements that aren’t out there in all browsers simply but.
How the polyfill works
Now we have now gained confidence in our random() polyfill, you is perhaps curious the way it works. Is that this a great time to stage with you and say I don’t absolutely know? That’s a really 2026 predicament, however fortunately it’s not due to AI.
As I hinted firstly, my stage of eagerness to make use of new CSS syntax earlier than it’s supported is matched solely by my stage of laziness to implement and preserve my very own model of random(), so I went looking for an open supply JavaScript implementation and was pleasantly stunned it exists!
As you would possibly anticipate, it’s not designed for the precise goal I need it for. it’s in an implementation that’s designed for use at build-time relatively than on the consumer, as a PostCSS plugin. Digging by the supply we see that this plugin wraps the MIT-licensed @csstools/css-calc which has no dependencies and isn’t coupled to PostCSS. The Readme for this bundle says it solely implements the older CSS Values and Models Module Stage 4, however we see from the commit historical past that it’s just lately had an “replace to newest spec” of random() and we see it passing automated assessments for the sort of random goodness we have now been having fun with on this article.
My major query is how on earth we're going to hook it as much as client-side CSS, however it seems to not be an excessive amount of customized code:
import { calc } from "@csstools/css-calc";
const calcFn = calc;
if (!CSS.helps("width", "random(0px, 100px)")) {
const styleTag = doc.createElement("type");
styleTag.textContent = ".randomized { show: none; }";
doc.head.appendChild(styleTag);
const elementIDs = new WeakMap();
const documentID = crypto.randomUUID();
doc.querySelectorAll(".randomized").forEach((factor) => {
const kinds = getComputedStyle(factor);
[...styles]
.filter((property) => property.startsWith("--random"))
.forEach((propertyName) => {
const css = kinds.getPropertyValue(propertyName);
const worth = resolveRandom(css, {
factor,
propertyName,
documentID,
elementIDs,
calcFn,
crypto,
});
factor.type.setProperty(propertyName, worth);
});
});
if (styleTag.parentNode) {
styleTag.parentNode.removeChild(styleTag);
}
}
operate resolveRandom(css, { factor, propertyName, documentID, elementIDs, calcFn, crypto }) {
const patchedCss = css.change(
/random(s*(?!(?:[^,]*b(?:shared|scoped)b|fixedb|--))([^,]+),/gi,
(_, expression) => `random(mounted ${Math.random()}, ${expression},`
);
return calcFn(patchedCss, {
precision: 5,
toCanonicalUnits: true,
randomCaching: {
documentID,
elementID: elementIDs.getOrInsert(factor, `element-${crypto.randomUUID()}`),
propertyName,
},
});
}
Let’s translate this code into pure language steps:
- If we detect that the browser helps native CSS
random(), then the polyfill will do nothing and let the browser deal with any calls in CSS torandom(). - If it doesn’t assist the function, we briefly conceal all components marked as
.randomizedto forestall a flicker. - We loop by all of the
--randomprefixed properties in any factor that has the.randomizedCSS class. - For every
--randomcustomized property, we reap the benefits of the truth that the “allowed syntax for customized properties is extraordinarily permissive,” which signifies that even when the CSS parser doesn't perceive an expression used within the worth for a property comparable to--random-grid-area: random(1, var(--rows), 1) / random(1, var(--columns), 1), the worth shall be parsed right into a string which might “be learn and acted on by JavaScript.” The browser may also resolve any calls tovar()and substitute these into the computed worth, no matter any surrounding gibberish it may well’t interpret. - We generate distinctive surrogate identifiers for the doc and every randomized factor we move to
@csstools/css-calcalong with the expression string that incorporates every utilization ofrandom(). This permits CSS Instruments to respect the random caching guidelines comparable toelement-shared. - If no base is laid out in a utilization of
random(), the library doesn’t appear to generate evenly distributed values (for instance, the celebs within the first check saved ending up in bizarre clusters), so we escape the proverbial duct tape and patch the issue by injecting a set randomly generated base worth if the person didn’t present one. - Utilizing the worth we get again from
@csstools/css-calcdecoding therandom()name, we set the property to that worth with an inline type on the randomized factor. - We take away the category declaration we injected to cover the randomized components whereas we have been resolving them.
Level 4 is a giant deal. Deciphering arbitrary customized property values utilizing CSS is the closest we have now in current day CSS to an honest-to-goodness documented extension level for the language. Since arbitrary expressions in customized variable values are legitimate and could be learn by JavaScript by way of the computed kinds, this strategy has the potential to keep away from most of the identified downsides of polyfilling CSS comparable to refetching and rewriting stylesheets, doing our personal parsing of CSS, and different enjoyable however harmful pastimes.
Random parting ideas
Fittingly, it’s solely by good luck that an open supply challenge has already performed a lot of the work we want to have the ability to run CSS random() in any browser whereas we anticipate native assist. Lots of people declare they'll’t anticipate this function to be out there in additional browsers, so will probably be fascinating to see whether or not folks select to attend now {that a} polyfill exists. Seeing Chris Coyier’s response to the starfield demo, his enthusiasm was contagious! I had an identical second after I first received the demo working in different browsers. Let me know if having this polyfill out there sparks creativity to your personal initiatives. I undoubtedly have concepts for some extra superior use circumstances for it, which is what prompted me to polyfill it.
Until subsequent time, blissful randomizing out of your pleasant neighbourhood random man.









