The creator of the TV present The Good Place wrote a tie-in ebook about ethical philosophy which features a chapter referred to as “The Luck of the Draw,” discussing how the fable of meritocracy leads folks to “underestimate the function 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 corresponding to generative UI are a useful utilization of unpredictable UX. Certainly, once I see the YouTube feedback reacting to Google’s upcoming utilization of GenUI in search, perhaps it’s taking the concept too far down a foul path. However there may be nonetheless one thing in regards to the thought of a webpage that exists in a state of refined flux every time you land on it, the identical method you possibly can’t step into the identical river twice.
Actual-world use instances for randomness
I’m a marketing consultant who usually works on short-term, greenfield initiatives, which give me with a window into the zeitgeist and the tendencies corporations suppose are the longer term. It’s no coincidence that the concept of randomness permeated one in every of my current initiatives. That’s epitomized by a burst of confetti to present the consumer a way of pleasure after they run a random draw they configured. And like many a UI characteristic 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.
Actually, the necessities grew to become customized sufficient that we ended up ditching the JavaScript plugin we have been utilizing and rolled our personal confetti implementation! This illustrates the strain between the conflicting wants for chaos and management in UX, even in a enjoyable characteristic like random confetti.
Wouldn’t it’s good if we might wield managed presentational randomness within the presentation layer with out leaving CSS?
The CSS random() perform emerges
If unpredictable consumer experiences are having a second, it follows that CSS will do its half to make randomized layouts simple to implement. The creators of CSS have all the time been on a mission to reap widespread UI patterns into declarative CSS requirements. Consistent with that spirit, we see that in late 2025, Safari grew to become the primary browser to help the CSS random() spec, as a part of an replace that emphasised “letting you clear up widespread use instances 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 example, Schalk Neethling confirmed us how CSS random() can provide us fine-grained management over the notorious confetti impact, and Alvaro Montoro made a robust argument that CSS seems to be essentially the most appropriate language for such duties. He factors out this method 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 unhealthy information: half a 12 months after Safari launched CSS random(), there isn’t readability on when it should 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 can 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 right, CSS random() is a part of an editor’s draft spec that’s within the “early exploration part” and “main breaking modifications are anticipated.”
On high of that, from my dive into CSS polyfills in my article on ::nth-letter, we all know the entire thought of a CSS polyfill could be a minefield.
With all these obstacles in thoughts, an individual must be a particular breed of loopy to aim to polyfill CSS random().
Let’s polyfill CSS random()
One of many commenters on a neat YouTube demo of the characteristic marvelled that it’s a “characteristic 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 associates on iPhones usually can’t run my experiments.
And but, within the case of random(), it’s darkly poetic {that a} characteristic primarily based on probability seems in an surprising place the place many people can’t use it. Actually, even Safari customers could profit from my css-random-polyfill package deal, as a result of Safari updates are tied to the OS, that means not everybody can improve to the newest model of the browser. In addition to, we all know how a lot Apple loves it whenever you hack their stuff to enhance compatibility.
Jokes apart, Apple appears severe in regards to the “hackability” and transparency of every part in regards to 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, through which the Apple Safari workforce confirmed off the chances 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 workforce’s article. It’s a randomly scattered discipline 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 authentic 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.
<!-- the script processes usages of css random on web page load -->
<script src="https://unpkg.com/css-random-polyfill@newest/dist/css-random-polyfill.js"></script>
<!-- 200 star divs, we add the "randomized" marker class so css-random-polyfill is aware of which components to focus on -->
<div class="randomized star"></div>
<div class="randomized star"></div>
<!-- and so forth. -->
<div class="randomized star fourpointed"></div>
<div class="randomized star fourpointed"></div>
<div class="randomized star fourpointed"></div>
<div class="randomized star fourpointed"></div>
<div class="randomized star fourpointed"></div>
As for the CSS, not like 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 help a brand new perform in CSS as an alternative of a brand new selector. It seems the CSS we are able to use on this scenario 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 anyplace we wish a random worth, we retailer it in an intermediate customized property, and we all the time should comply with 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%);
high: 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 number of completely different variations of the supported random() syntax, corresponding to the elective 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);
}
Notice: Within the authentic 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 perform “can be utilized instead of any a part of any property’s worth,” identical 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 suitable with the native implementation: we might delete the script reference to the polyfill as soon as native help goes baseline and our code will nonetheless work, prefer it does right now when it detects native help 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. It is a compromise I can dwell with, particularly if the choice is to press our noses in opposition to the glass of Safari-only demos on YouTube and make feedback corresponding 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 once I was testing my polyfill, that demo was enjoyable to observe randomly twinkling, refresh and see the celebs scatter in a different way utilizing an emergent, declarative CSS customary. 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 workforce feels a bit like a contrived excuse to randomize one thing. Nevertheless, it did assist me take a look at the polyfill help of some completely different variations of the syntax.
The polyfill permits for some versatile syntax. You may see that references to customized properties handed to the random() perform get substituted as anticipated, and you’ll see that inlining a number of random() calls in the identical worth works. For instance, we are able to 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 workforce. To proceed the themes of probability and synchronicity, I’ll point out that I had the great fortune to fulfill Tim final 12 months once I spoke at Internet Instructions 2025. My speak got here proper after his speak, 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 comply with.
You may see on this instance that the ultimate random place of the wheel makes use of a special 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 combination of sorts is supported as a result of the specs say the values have to be “resolvable to the identical knowledge sort,” so we’re capable of combine models so long as they’re in the identical “general knowledge sort,” corresponding to flip and deg, acquainted from the best way CSS calc() provides values with completely different models when it is smart, utilizing CSS typed arithmetic.
Notice: To make the demo work with the polyfill, I needed to outline the variable in a CSS class that might be utilized when the polyfill first masses, in distinction to Tim’s authentic demo which makes use of the random() perform inside a keyframes animation that was utilized primarily based on a checkbox hack. That’s as a result of, for now, the polyfill solely processes the computed types which might be utilized to components when the web page first masses. Since all my checks go with this implementation, I’m leaving it like that for now within the curiosity of doing the only factor that might probably work. There are methods we might discover to make the polyfill react to dynamic modifications to the computed types and/or the DOM.
Demo: Random squares
Chris Coyier has a knack for writing code that’s both as tough 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() attainable, displaying three randomly positioned squares with random colours. Under is my cross-browser model, which I additionally modified to randomize the dimensions of the squares, as a take a look at 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 might be extra helpful in the true native model, which received’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 perform
Lots of the above demos embrace random colours. That’s achieved by passing random numeric values into CSS colour capabilities corresponding to rgb() or lch(). But when we had an inventory of particular colours we needed to randomly select from, we are able to’t try this simply, which is why the spec for the CSS values and models module mentions the random-item() perform, though no browser at present implements it (aside from experimental help in safari preview). If we had this perform, we might choose a random colour or anything from an arbitrary checklist of values:
random-item(element-shared, crimson, blue, inexperienced);
The random-item perform takes a compulsory first argument of the sort random-caching-options, the identical as CSS random(), however then it takes a variable size checklist of arguments to randomly choose from, moderately than a minimal and most worth.
I don’t really feel like complicating the polyfill to help a CSS syntax that isn’t carried out in any browser — evidently I solely give myself permission to try this yearly. However now that we now have 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 bizarre 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);
When you’re utilizing a Chromium-based browser, you possibly can see the code in motion on this model of the squares demo which units all three components to the identical colour randomly chosen from the checklist.
The implementation of my generic --item customized CSS perform takes an --index argument adopted by 10 elective arguments. These might be elevated to any variety of arguments you suppose would be the sensible most dimension of a group you would wish. Every of the elective arguments is made elective by defaulting it to an empty worth, so the caller of the perform solely must go within the arguments it must index. Lastly, the perform maps the --index to the argument at that index, as a result of CSS customized capabilities don’t help variable size collections of arguments the best way JavaScript capabilities do.
@perform --item(--index,
--arg-1: ,
--arg-2: ,
--arg-3: ,
--arg-4: ,
--arg-5: ,
--arg-6: ,
--arg-7: ,
--arg-8: ,
--arg-9: ,
--arg-10: ) {
consequence: if(
fashion(--index: 1): var(--arg-1);
fashion(--index: 2): var(--arg-2);
fashion(--index: 3): var(--arg-3);
fashion(--index: 4): var(--arg-4);
fashion(--index: 5): var(--arg-5);
fashion(--index: 6): var(--arg-6);
fashion(--index: 7): var(--arg-7);
fashion(--index: 8): var(--arg-8);
fashion(--index: 9): var(--arg-9);
else: var(--arg-10);
);
}
Sidenote: This generic helper perform is fascinating, as a result of Temani Afif has demonstrated cool use instances for having the ability to select from an inventory of colours utilizing an --index variable, however the answer he created was particular to the colour knowledge sort and he freely admits it’s “extra of a hack than a CSS characteristic. So, use it cautiously.” Against this, the customized perform method will work with an inventory of any knowledge sort, 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 now have gained confidence in our random() polyfill, you may be curious the way it works. Is that this a very good time to degree 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 degree of eagerness to make use of new CSS syntax earlier than it’s supported is matched solely by my degree 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 shocked it exists!
As you may count on, it’s not designed for the precise function I need it for. it’s in an implementation that’s designed for use at build-time moderately than on the consumer, as a PostCSS plugin. Digging via 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 package deal says it solely implements the older CSS Values and Items Module Stage 4, however we see from the commit historical past that it’s lately had an “replace to newest spec” of random() and we see it passing automated checks for the sort of random goodness we now have been having fun with on this article.
My important 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("fashion");
styleTag.textContent = ".randomized { show: none; }";
doc.head.appendChild(styleTag);
const elementIDs = new WeakMap();
const documentID = crypto.randomUUID();
doc.querySelectorAll(".randomized").forEach((component) => {
const types = getComputedStyle(component);
[...styles]
.filter((property) => property.startsWith("--random"))
.forEach((propertyName) => {
const css = types.getPropertyValue(propertyName);
const worth = resolveRandom(css, {
component,
propertyName,
documentID,
elementIDs,
calcFn,
crypto,
});
component.fashion.setProperty(propertyName, worth);
});
});
if (styleTag.parentNode) {
styleTag.parentNode.removeChild(styleTag);
}
}
perform resolveRandom(css, { component, propertyName, documentID, elementIDs, calcFn, crypto }) {
const patchedCss = css.substitute(
/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(component, `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 help the characteristic, we quickly cover all components marked as
.randomizedto forestall a flicker. - We loop via all of the
--randomprefixed properties in any component that has the.randomizedCSS class. - For every
--randomcustomized property, we make the most of the reality that the “allowed syntax for customized properties is extraordinarily permissive,” which implies that even when the CSS parser doesn’t perceive an expression used within the worth for a property corresponding to--random-grid-area: random(1, var(--rows), 1) / random(1, var(--columns), 1), the worth might be parsed right into a string which may “be learn and acted on by JavaScript.” The browser will even resolve any calls tovar()and substitute these into the computed worth, no matter any surrounding gibberish it will probably’t interpret. - We generate distinctive surrogate identifiers for the doc and every randomized component we go to
@csstools/css-calcalong with the expression string that incorporates every utilization ofrandom(). This enables CSS Instruments to respect the random caching guidelines corresponding 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 take a look at stored ending up in bizarre clusters), so we escape the proverbial duct tape and patch the issue by injecting a hard and fast randomly generated base worth if the consumer 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 fashion on the randomized component. - We take away the category declaration we injected to cover the randomized components whereas we have been resolving them.
Level 4 is an enormous deal. Decoding arbitrary customized property values utilizing CSS is the closest we now have 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 types, this method has the potential to keep away from most of the recognized downsides of polyfilling CSS corresponding 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 finished a lot of the work we’d like to have the ability to run CSS random() in any browser whereas we look ahead to native help. Lots of people declare they’ll’t look ahead to this characteristic to be out there in additional browsers, so it is going to 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 analogous second once I first received the demo working in different browsers. Let me know if having this polyfill out there sparks creativity in your personal initiatives. I undoubtedly have concepts for some extra superior use instances for it, which is what prompted me to polyfill it.
Until subsequent time, pleased randomizing out of your pleasant neighbourhood random man.

