CSS random() Ships in Safari and Chrome 156: A Design Guide
Safari and Chrome 156 now ship native CSS random() from Values and Units Level 5, enabling pseudo-random tilts, timing and sizes in pure stylesheets — with caching keys, step rounding and accessibility caveats.
- AuthorRebecca Stone
- ChannelDesign Tools
- Filed
- Read3 min

- CSS random() is defined in CSS Values and Units Module Level 5 and has shipped in Safari; Chrome 156 is rolling it out now.
- Firefox shows positive signals on the standards track but has not shipped the function.
- Caching keys like --square-size share one random value across properties, keeping elements perfectly square.
- The companion random-item() function for token lists has no browser support yet.
- Animations built with random() must respect prefers-reduced-motion, and split-letter headings need aria-label plus aria-hidden spans.
By Rebecca Stone
Safari has shipped the native CSS random() function, and Chrome 156 is rolling it out now, with positive signals from Mozilla on Firefox's standards track. The function, defined in CSS Values and Units Module Level 5, generates pseudo-random values inside stylesheets with zero JavaScript and no build-time Sass loops.
For design engineers, that's a real shift. A decade of tokens, spacing scales and grid discipline has made the web predictable — and, as the original author puts it, sometimes sterile. Interfaces built by unguided LLMs tend to reproduce that same squared-off, aligned look. random() offers a way to add what the source calls "controlled chaos": small, deliberate imperfections.
How does the function actually work?
The spec syntax is random(<random-caching-key>?, <min>, <max> [, by <step>]?). In practice, browsers accept comma-separated arguments:
rotate: random(-3deg, 3deg)— a random angleinline-size: random(20px, 80px, 10px)— random width in 10px stepsanimation-duration: random(1.5s, 3s, 0.2s)— random timing
Two constraints matter. First, min and max must share the same unit type — you cannot mix 2rem with 100px; reach for calc() if you need to combine units. Second, the optional step argument rounds values to discrete increments, so random(0px, 60px, 15px) produces only 0, 15, 30, 45 or 60px. That keeps jitter landing on your predefined grid.
The caching key solves a subtler problem. Normally each random() evaluation is independent, so an element with random width and height becomes a mismatched rectangle. Share a key — random(--square-size, 60px, 120px) on both inline-size and block-size — and the engine reuses one computed value, guaranteeing a clean 1:1 square.
What can you build with it?
The source walks through six CodePen demos:
- Organic typography. Per-character tilts (
random(-2.8deg, 2.8deg)), micro-translations and opacity variance that mimic vintage letterpress — snapping straight on hover. - Procedural bounce. Per-letter jump heights and durations, plus a negative animation delay (
random(-3s, 0s)) so letters are already mid-bounce at page load. - Tilting cards. Random rotation with box-shadows computed from the tilt angle, straightening on hover and keyboard focus.
- A splayed card deck.
sibling-index()handles the mathematical fan — each card rotates a fixed 12deg regardless of count — whilerandom()adds hand-dealt wobble, all driven byanimation-timeline: scroll(root). - Random velocity marquees.
calc(pow(-1, sibling-index()))alternates row direction;random(15%, 44%)sets each row's scroll-linked travel distance. - Fake bokeh.
filter: blur(random(0px, 8px, 1px))with random opacity and scale recreates shallow depth of field, rack-focusing on hover.
Where does randomness belong?
The guidance is firm. Good fits: decorative micro-imperfection, desynchronized ambient loops, generative backgrounds, editorial art direction. Bad fits: core layouts and grids, body copy typography, and interactive targets left crooked without a hover or focus reset.
Two accessibility rules apply. Splitting a word into letter spans breaks screen readers, which read out characters individually — so hide the visual spans with aria-hidden="true" and provide aria-label="Imperfection" on the heading. And every animation must sit behind prefers-reduced-motion: reduce; the source also suggests flattening random angles there, not just stopping motion.
During the rollout phase, wrap experiments in @supports (rotate: random(-2deg, 2deg)) with a static fallback baseline. The spec also defines a companion random-item() that picks from a list of tokens — say, oklch() palette colors — though no browser supports it yet.
The piece closes on a wager: with consistency, tokens and design systems now mastered, the foundation exists to let playful messiness back onto the web — at zero JavaScript cost.
Original: w3.org
More from Rebecca Stone
Show full bio
News editor covering technology and product news in Product and interaction design, design systems at Interface Wire.
50 articles