Skip to main content

Bringing Chance to the Style Sheet: Polyfilling the Emergent CSS random() Function Across Browsers

In his tie-in book on moral philosophy, How to Be Perfect, Michael Schur—creator of the acclaimed television series The Good Place—devotes a chapter titled “The Luck of the Draw” to examining the pervasive myth of meritocracy. Schur argues that belief in pure meritocracy frequently causes individuals to dramatically underestimate the pivotal role that luck plays in shaping their fortunes.

That philosophical tension between deterministic control and arbitrary chance has increasingly migrated into the digital realm. As web experiences embrace controlled chaos and dynamic variability, art is visibly imitating life. Designers and developers are experimenting with probabilistic user experiences, ranging from subtle layout shifts each time a page loads to full-fledged generative user interfaces.

While extreme expressions of nondeterminism, such as Google’s planned deployment of generative UI within search results, have elicited mixed reactions from users online, there remains a compelling aesthetic appeal to the idea of a webpage existing in a state of continuous, subtle flux. Much like the ancient HeraclITEan adage that one cannot step into the same river twice, probabilistic layout techniques offer a web experience that feels inherently alive.

Real-World Use Cases for Randomness

The demand for controlled presentational randomness is far from a purely theoretical pursuit. In modern client consulting—particularly on short-term, greenfield software initiatives—emergent design trends quickly manifest as concrete client demands.

In one recent corporate project, a client requested a visually engaging confetti explosion to celebrate when a user triggers a configured random draw. While the concept was simple in principle, corporate branding requirements swiftly complicated the implementation. To ensure every randomized particle complied strictly with brand guidelines, the development team was forced to abandon a standard third-party JavaScript plugin and engineer a custom solution from scratch.

That development effort underscored an enduring friction in user interface engineering: balancing chaotic visual design with rigorous control. It also raised a fundamental architectural question for web developers: why rely on heavy JavaScript libraries for purely visual, randomized behavior when such presentation logic could reside directly within CSS?

The history of CSS standards development is defined by a consistent mission to absorb common user interface patterns into declarative rules, effectively formalizing established development practices into standard syntax while adhering to the web’s Rule of Least Power. In late 2025, Apple’s WebKit team took a major step toward standardizing presentational chance by introducing native support for the CSS random() function in Safari 26.2. The release highlighted a broader effort to solve frequent web presentation challenges directly within HTML and CSS, minimizing reliance on client-side JavaScript execution.

The arrival of native CSS randomness prompted immediate enthusiasm across the front-end community. Developer Schalk Neethling demonstrated how declarative CSS randomness could grant fine-grained control over complex particle animations like confetti, while author Alvaro Montoro argued that CSS is natively the most appropriate layer for presentational randomness under the Rule of Least Power.

However, cross-browser support remains significantly fragmented. Half a year after Safari introduced native implementation, neither Google Chrome nor Mozilla Firefox has delivered a release timeline for the feature. While open issue trackers in both the Chromium and Bugzilla projects show active development, developers outside the Apple software ecosystem remain unable to utilize native CSS random() without polyfills, even behind experimental browser flags.

Compounding the problem, the underlying specification—part of the CSS Values and Units Module Level 5—remains an early-stage Editor’s Draft. The syntax incorporates intricate value-caching semantics, keying options, base values, and step intervals, all subject to future breaking changes. Furthermore, historical attempts to polyfill CSS features have often introduced severe performance penalties, rendering cross-browser implementations notoriously difficult to construct safely.

Let’s Polyfill CSS random()

The initial exclusivity of CSS random() to WebKit created a unusual dynamic in web development. Traditionally, emerging CSS standards debut within Chromium-based engines before making their way to WebKit, often leaving iOS web browsers waiting for feature parity due to platform engine restrictions.

In the case of random(), the feature’s unexpected initial restriction to Safari created a practical dilemma. Because Safari browser updates remain tied directly to macOS and iOS system updates, even users within Apple’s ecosystem frequently run older versions lacking native support for the newest CSS features.

To bridge this cross-browser gap, an open-source library named css-random-polyfill was developed. Designed to bring cross-browser functionality to modern CSS randomness, the polyfill relies on techniques adapted from original WebKit technical demonstrations published during Safari’s early preview period.

Demo: Random Starfield

One of the prominent technical demonstrations published by Apple’s WebKit team featured a dynamic, randomly generated starfield. In the original demo, two hundred star elements fade in and out at varied intervals against a dark background. Larger, four-pointed stars tilt at uniform, randomly generated angles, while each star casts subtle, randomized shadows using modern color spaces.

Migrating this demonstration to function across Chrome, Firefox, and older Safari releases requires including the polyfill script and marking target elements with a specific class selector, such as .randomized.

In contrast to polyfills that attempt to invent non-standard CSS selectors, polyfilling a CSS function involves handling syntax that browser parsers recognize as standard custom property assignments. Rather than executing functions directly inline within standard properties, the polyfill uses intermediate CSS custom properties prefixed with --random.

For instance, star sizing, positioning, color hue values, and animation speeds are declared using scoped variables:

.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 setup demonstrates several features of the random() specification, including step intervals—such as restricting star sizes to whole pixel increments between 1px and 7px—and shared key scopes. By leveraging the element-shared parameter, all four-pointed star elements receive an identical, randomly assigned rotation angle across the entire document:

.star.fourpointed 
  --random-rotation: random(element-shared, -45deg, 45deg);
  rotate: var(--random-rotation);

While inline random() declarations represent the ultimate goal of the specification, using intermediate custom properties allows the polyfill to process mathematical values safely without breaking existing stylesheets. When executed in Safari environments with native support, the polyfill bypasses processing entirely, allowing the native WebKit engine to take over smoothly.

Demo: Random Colored Grid Cells

Following the publication of WebKit’s starfield example, web developer Chris Coyier noted the compelling visual capabilities of declarative CSS randomness. A secondary example created by the Safari engineering team involved generating a 100-by-100 CSS grid containing multi-colored, randomly sized grid cells.

While generating hundreds of multi-colored grid squares serves primarily as a stress test for layout engines, it provides an effective baseline for validating complex expression parsing. The polyfill successfully handles nested variable substitutions and multiple random() assignments within property value shorthands, such as dynamically assigning grid-area boundaries:

.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 demonstration, engineered by WebKit developer Tim Nguyen, illustrates animated rotational physics through a spinning prize wheel layout.

This implementation highlights the spec’s support for mixed CSS unit types. The random() function allows combining distinct units—such as angular turns and degrees—provided they resolve to the same underlying physical data type:

@keyframes spin 
  from 
    rotate: 0deg;
  
  to 
    rotate: var(--random-rotation);
  


#wheel 
  --random-rotation: random(2turn, 10turn, 20deg);

In this context, CSS typed arithmetic processes the minimum bound (2turn), maximum bound (10turn), and rotational step increment (20deg) seamlessly.

To ensure stability across engines, the current polyfill evaluates computed styles upon initial page load. While future iterations could incorporate dynamic DOM mutation observers or reactive style recalculations, performing a clean evaluation on load satisfies the primary requirements for static presentational layouts.

Demo: Random Squares

A simplified demonstration, adapted from minimal test cases created by Chris Coyier, features three randomly positioned squares with randomized sizing and background hues.

This test case verifies support for custom caching keys, which synchronize random seed values across independent properties on the same element:

--random-height: random(--side, 40px, 100px);
--random-width: random(--side, 40px, 100px);

width: var(--random-height);
height: var(--random-width);

By passing a matching custom key identifier (in this case, --side), both width and height properties receive identical values, guaranteeing perfectly square aspect ratios without requiring duplicate manual variable declarations.

Chromium-Only Bonus Demo: Simulating random-item() Using a Custom CSS Function

While numerical ranges are handled cleanly by random(), designers frequently need to select at random from discrete lists of non-numeric values, such as specific brand colors or font stacks. To address this, the CSS Values and Units Module Level 5 draft proposes a dedicated random-item() function:

random-item(element-shared, red, blue, green);

Beyond experimental preview implementations in Safari Technology Preview, random-item() remains unsupported in production browser builds. However, in Chromium engines supporting experimental CSS Custom Functions (@function) and inline conditional logic (if()), developers can simulate list selection behavior by combining custom functions with numerical random() evaluations.

By declaring a custom --item() function that maps numerical index values to specific positional arguments, developers can evaluate discrete item selections using standard CSS rules:

--random-index: random(element-shared, 1, 5, 1);
--random-color: --item(var(--random-index), aqua, purple, pink, grey, green);

The underlying implementation relies on establishing default fallback values for optional positional parameters and evaluating index matches through 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 earlier CSS array workarounds restricted specifically to color data types, combining modern custom functions with conditional style evaluation allows generic item selection across any valid CSS value type using upcoming browser standards.

How the Polyfill Works

Underneath the execution layer, css-random-polyfill delegates heavy mathematical parsing and caching calculations to established open-source tooling. The polyfill builds upon the @csstools/css-calc package—originally maintained for build-time PostCSS processing—which was updated to implement Level 5 CSS random() specifications and caching semantics.

When imported into a browser environment, the client-side JavaScript execution sequence proceeds through clear operational steps:

  1. Feature Detection: The script checks native browser support using CSS.supports("width", "random(0px, 100px)"). If native support is detected, execution halts immediately, allowing the engine to process the spec natively.
  2. Flash of Unstyled Content Prevention: If support is absent, a temporary <style> tag is appended to the document head to hide target elements marked with .randomized during evaluation.
  3. Instance Tracking Initialization: A WeakMap is instantiated to map DOM elements to unique runtime identifiers, alongside a global document UUID generated via crypto.randomUUID().
  4. Computed Style Inspection: The script queries all elements bearing the .randomized class and inspects their computed styles specifically for custom properties prefixed with --random.
  5. Expression Parsing: Unresolved mathematical string expressions are passed to @csstools/css-calc, enriched with contextual caching metadata including document IDs, element UUIDs, and variable scope rules.
  6. Value Application and Cleanup: Resolved canonical unit strings are applied directly to the target element’s inline style declarations. Finally, the temporary hiding stylesheet is removed from the document head.
import  calc  from "@csstools/css-calc";
const calcFn = calc;

if (!CSS.supports("width", "random(0px, 100px)")) 
  const styleTag = document.createElement("style");
  styleTag.textContent = ".randomized  display: none; ";
  document.head.appendChild(styleTag);
  const elementIDs = new WeakMap();
  const documentID = crypto.randomUUID();

  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);
    );
  );
  if (styleTag.parentNode) 
    styleTag.parentNode.removeChild(styleTag);
  


function resolveRandom(css,  element, propertyName, documentID, elementIDs, calcFn, crypto ) fixedb

Reading arbitrary custom property values via getComputedStyle() provides a robust extension point for browser CSS. Because browsers treat arbitrary expressions inside CSS variables as valid syntax, this pattern avoids the major pitfalls historically associated with CSS polyfills, such as fetching raw stylesheet files over the network, manually parsing full CSS rulesets, or interrupting standard cascade inheritance.

Random Parting Thoughts

The availability of client-side polyfills allows front-end developers to experiment immediately with declarative randomness without waiting for multi-year browser engine alignment.

As web standards continue absorbing complex presentation logic, bringing controlled unpredictability into the stylesheet layer opens up creative opportunities for web design. Whether utilized for organic layout shifts, brand-compliant animation effects, or generative background structures, declarative randomness offers a performant, standards-aligned path toward a more dynamic web interface.

Nana Muazin

Author at DesignEnt.

Flash News