In his companion book How to Be Perfect, Michael Schur, creator of the critically acclaimed television series The Good Place, devotes a chapter titled "The Luck of the Draw" to examining the myth of meritocracy. Schur argues that individuals routinely underestimate the profound role that pure chance plays in shaping their lives. In a universe where physical reality often appears to play dice, a compelling parallel has emerged across digital product design: websites and applications are increasingly embracing controlled chaos in their user interfaces.
The shift toward probabilistic user experience (UX) thinking has sparked widespread debate across the web development community. While extreme implementations such as generative UI—including Google’s efforts to integrate dynamically generated layouts into search results—have drawn mixed reactions, the concept of a webpage existing in a state of subtle flux each time a user lands on it carries enduring appeal. Like the ancient Greek philosopher Heraclitus famously observed, one cannot step into the same river twice; modern web design is beginning to echo that sentiment.
Real-World Use Cases for Randomness
In greenfield project consulting, client demands often provide a direct window into emerging design trends and technological priorities. Across contemporary web projects, elements of controlled randomness have rapidly transitioned from conceptual novelty to functional design requirements. A common example is the integration of randomized confetti bursts used to elevate user engagement when triggering successful draw configurations.
Yet, even simple visual flair frequently collides with strict corporate branding requirements. Standard JavaScript libraries often fall short when every randomized particle must strictly conform to dynamic palette rules, brand geometries, or strict motion guidelines. In many development environments, teams end up abandoning third-party plugins to build custom in-house confetti implementations. This recurring effort highlights a fundamental tension in modern frontend development: balancing the conflicting needs for structural control and dynamic visual chaos.
This tension raises a practical question for web engineers: why shouldn’t front-end developers be able to harness presentational randomness directly within the CSS presentation layer, without relying on heavy JavaScript execution?
Historically, the World Wide Web Consortium (W3C) and browser vendors have advanced CSS by standardizing common user interface patterns into declarative rules—a philosophy often referred to as "paving the cowpaths." Following this convention, Apple’s WebKit team made Safari the first browser to ship native support for the CSS random() specification as part of the Safari 26.2 release in late 2025. The update was positioned around a clear objective: allowing developers to resolve common layout and visual use cases using pure HTML and CSS, reducing reliance on external JavaScript frameworks.
/* Native CSS random() syntax introduced in Safari 26.2 */
.particle
top: random(0%, 100%);
left: random(0%, 100%);
background-color: oklch(0.6 0.2 random(0, 360));
The release of native random() in WebKit ignited immediate interest among web developers. Software engineer Schalk Neethling showcased how native CSS randomness allows for granular control over complex particle systems like confetti, while web developer Alvaro Montoro argued that CSS is naturally the most appropriate layer for presentational logic. Montoro emphasized that moving presentation randomness into CSS aligns directly with the web’s Rule of Least Power, which advises solving engineering problems using the least powerful language capable of expressing the solution.
However, cross-browser availability remains a major bottleneck. Half a year after Safari introduced CSS random(), there is still no definitive timeline for when the feature will land natively in competing browser engines. Active tracker entries in both the Chromium project (Issue 413385732) and Mozilla Firefox’s Bugzilla (Bug 1836588) indicate ongoing development, but neither platform offers concrete guarantees for general availability or flag-enabled testing.
For engineers working across platforms, this fragmenting implementation means native CSS random() demos run seamlessly on modern macOS devices while failing on Windows or Linux workstations. Building a client-side polyfill to bridge this gap presents significant technical hurdles. The underlying syntax defined in the CSS Values and Units Module Level 5 editor’s draft is intricate, featuring elaborate caching and keying semantics, combined with strict rules for base values, ranges, and step intervals. Furthermore, because the specification remains in an early exploration phase, breaking spec updates remain possible.
/* Complex native syntax featuring caching options and step intervals */
.star
--random-rotation: random(element-shared, -45deg, 45deg);
--random-size: random(1px, 7px, 1px);
Combined with the well-known architectural pitfalls of parsing custom CSS rules at runtime, polyfilling emerging CSS functions is notoriously difficult. Yet, the demand for cross-browser visual experimentation has driven developers to seek functional client-side solutions.
Let’s Polyfill CSS random()
The initial exclusivity of CSS random() to Safari created an unusual reversal in web development norms. Developers accustomed to testing emergent web features first in Chromium engines found themselves locked out unless working within Apple’s ecosystem. However, even within Apple’s user base, reliance on native browser updates poses accessibility challenges; Safari updates remain tied to full operating system releases, leaving users on older macOS or iOS versions unable to execute native random() declarations.
To bridge these gaps, developers have turned to open-source tooling, yielding client-side libraries such as css-random-polyfill. Designed to execute across all modern desktop and mobile browsers, the package polyfills CSS random() declarations by evaluating custom variable expressions at runtime.
Much of the groundwork for testing client-side polyfilling stems from original WebKit technical demonstrations released by the Apple Safari team when the feature first appeared in Safari Technology Preview.
Demo: Random Starfield
One of the flagship demonstrations published by the WebKit team features a dynamic night sky filled with randomly scattered, twinkling stars. Larger four-pointed stars tilt uniformly at a single randomly selected angle, while every individual star projects subtle drop-shadows with varied hues and animation delays.
To convert this Safari-only demonstration into a cross-browser implementation, markup structures require a lightweight polyfill script reference alongside a marker class (such as randomized) applied to target elements:
<!-- The polyfill script evaluates usages of CSS random on initial page load -->
<script src="https://unpkg.com/css-random-polyfill@latest/dist/css-random-polyfill.js"></script>
<!-- Elements utilize a marker class so the polyfill identifies target nodes -->
<div class="randomized star"></div>
<div class="randomized star"></div>
<div class="randomized star fourpointed"></div>
<div class="randomized star fourpointed"></div>
Unlike experimental polyfills for custom selectors—which require complex CSS parsing and stylesheet rewriting—polyfilling a CSS function can leverage valid CSS custom property declarations. In this setup, developers assign native random() calls to custom properties prefixed with --random:
.star
--random-star-size: random(1px, 7px, 1px);
background-color: white;
border-radius: 50%;
aspect-ratio: 1/1;
width: var(--random-star-size);
position: fixed;
--random-top: random(0%, 100%);
--random-left: random(0%, 100%);
top: 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: normal;
This starfield example highlights key elements of the Level 5 specification, including optional step intervals. By passing 1px as the third parameter in random(1px, 7px, 1px), the evaluation is constrained strictly to whole-number increments within the defined range.
To achieve uniform alignment across distinct nodes, the specification defines the element-shared keyword. In the starfield demo, this key ensures every four-pointed star shares the exact same rotation angle:
.star.fourpointed
--random-rotation: random(element-shared, -45deg, 45deg);
rotate: var(--random-rotation);
While native browser implementations allow random() to be declared inline anywhere standard math functions like calc() or min() are valid, assigning expressions to standard custom properties ensures broad backwards compatibility. When executed in modern Safari, the polyfill detects native support and defers directly to the browser engine, bypassing execution overhead entirely.
Demo: Random Colored Grid Cells
Beyond atmospheric background animations, the specification supports complex programmatic layout mechanics. Web development writer Chris Coyier highlighted the flexibility of combining declarative randomness with modern layout engines like CSS Grid.
In a 100×100 grid setup, individual grid items can evaluate randomized start and end coordinates. The polyfill handles nested variable substitutions and multiple inline random() expressions contained within a single rule, enabling dynamic assignments for shorthand properties like grid-area:
.rectangle
--random-grid-area: random(1, var(--rows), 1) / random(1, var(--columns), 1);
grid-area: var(--random-grid-area);
Demo: Wheel of Fortune
A third major demonstration, originally developed by WebKit engineer Tim Nguyen and showcased at industry events like Web Directions 2025, uses CSS randomness to drive physical mechanics simulations, such as a spinning wheel of fortune.
@keyframes spin
from
rotate: 0deg;
to
rotate: var(--random-rotation);
#wheel
--random-rotation: random(2turn, 10turn, 20deg);
This implementation highlights the specification’s unit resolution rules. Under the CSS Values and Units Module Level 5 draft, parameters supplied to random() must resolve to identical base data types. However, distinct units within the same dimensional category can be mixed freely—such as combining turns (turn) and degrees (deg) for rotational values—leveraging CSS typed arithmetic to calculate output bounds.
To maintain performant execution, client-side polyfills typically evaluate computed styles upon initial DOM load. While dynamic re-evaluation in response to live state modifications or CSS keyframe cycles remains a technical boundary under active exploration, static initial evaluations satisfy the majority of presentational layout needs.
Demo: Random Squares
To test synchronization capabilities across discrete properties, developers often look to basic foundational layouts. A minimal demonstration inspired by Coyier’s work displays randomly generated squares with variable dimensions and positions.
To ensure an element maintains a perfect 1:1 aspect ratio while randomizing its overall footprint, the CSS random() spec introduces custom key identifiers for random value sharing:
--random-height: random(--side, 40px, 100px);
--random-width: random(--side, 40px, 100px);
width: var(--random-height);
height: var(--random-width);
By specifying matching identifier keys (in this case, --side), the evaluation engine guarantees that both declarations resolve to the identical calculated value for any given element instance.
Chromium-Only Bonus Demo: Simulating random-item Using a Custom CSS Function
While generating random numbers, lengths, and angles covers many layout needs, modern UI design frequently demands picking non-numeric design tokens—such as specific visual themes or brand colors—from a fixed list. To address this, the W3C spec outlines a dedicated random-item() function:
/* Spec proposal for picking from non-numeric parameter lists */
color: random-item(element-shared, red, blue, green);
With the exception of experimental flags in Safari Technology Preview, native random-item() support is not yet broadly available in main release channels. However, experimental builds of Chromium now support modern CSS features like custom functions (@function) and inline conditionals (if()). By combining these emergent standards with polyfilled or native numerical random() calls, developers can construct a functional equivalent for discrete list selection:
--random-index: random(element-shared, 1, 5, 1);
--random-color: --item(var(--random-index), aqua, purple, pink, grey, green);
The supporting custom function maps numerical index arguments against discrete parameters using conditional inline style queries:
@function --item(--index,
--arg-1: ,
--arg-2: ,
--arg-3: ,
--arg-4: ,
--arg-5: ,
--arg-6: ,
--arg-7: ,
--arg-8: ,
--arg-9: ,
--arg-10: )
result: if(
style(--index: 1): var(--arg-1);
style(--index: 2): var(--arg-2);
style(--index: 3): var(--arg-3);
style(--index: 4): var(--arg-4);
style(--index: 5): var(--arg-5);
style(--index: 6): var(--arg-6);
style(--index: 7): var(--arg-7);
style(--index: 8): var(--arg-8);
style(--index: 9): var(--arg-9);
else: var(--arg-10);
);
Unlike historical workarounds that relied on data-type-specific hacks—such as mapping indices into specific color channels—custom CSS functions operate abstractly across arbitrary data types, offering a clean preview of how list selection functions will operate once fully standardized.
How the Polyfill Works
Under the hood, modern client-side polyfills leverage established build-time parsing engines to process CSS mathematical expressions in the browser. Rather than building spec-compliant mathematical evaluation logic from scratch, libraries like css-random-polyfill wrap open-source parsing modules originally created for post-processing pipelines, such as CSSTools’ @csstools/css-calc.
import calc from "@csstools/css-calc";
const calcFn = calc;
// Native feature detection check
if (!CSS.supports("width", "random(0px, 100px)"))
// Inject temporary style tag to prevent layout flash during script processing
const styleTag = document.createElement("style");
styleTag.textContent = ".randomized display: none; ";
document.head.appendChild(styleTag);
const elementIDs = new WeakMap();
const documentID = crypto.randomUUID();
// Query and process target elements
document.querySelectorAll(".randomized").forEach((element) =>
const styles = getComputedStyle(element);
[...styles]
.filter((property) => property.startsWith("--random"))
.forEach((propertyName) =>
const css = styles.getPropertyValue(propertyName);
const value = resolveRandom(css,
element,
propertyName,
documentID,
elementIDs,
calcFn,
crypto,
);
element.style.setProperty(propertyName, value);
);
);
// Remove temporary visibility guard once styles are applied
if (styleTag.parentNode)
styleTag.parentNode.removeChild(styleTag);
function resolveRandom(css, element, propertyName, documentID, elementIDs, calcFn, crypto )
// Normalize un-keyed random calls by injecting implicit unique seeds
const patchedCss = css.replace(
/random(s*(?!(?:[^,]*b(?:shared
The polyfill’s execution flow follows a structured, non-destructive path:
- Feature Detection: The script issues a
CSS.supports()query to check if the user agent natively parsesrandom(). If the browser passes the feature check, execution terminates immediately. - Flash of Unstyled Content Guarding: On non-supporting engines, the script dynamically injects a temporary CSS rule hiding elements marked with the target class, preventing visible visual layout jumps while values compute.
- DOM & Style Inspection: The script queries target elements and reads their computed custom properties via
getComputedStyle(). It filters specifically for properties matching the designated naming convention (--random*). - Custom Property Abstraction: Extracting custom variables directly from computed styles allows the script to read valid CSS expressions without fetching, re-parsing, or altering external stylesheets—avoiding the primary performance penalties historically associated with CSS polyfills.
- Spec Normalization & Calculation: The engine injects explicit fallback scope parameters where omitted, then delegates key tracking and mathematical value resolution to
@csstools/css-calc. - DOM Mutation & Restoration: Resolved values are written back to the element’s inline style attributes, updating target CSS variables. Finally, the temporary visibility style tag is unmounted from the DOM, revealing the randomized presentation seamlessly.
By treating CSS custom properties as an extension layer, developers can safely experiment with emergent standards today. As native adoption expands across Chromium and Gecko browser engines over time, projects utilizing standardized parameter structures can remove polyfill script tags without requiring updates to their underlying CSS architecture.