WebKit/Safari has rolled out a preview version of random()
in CSS.
Random functions in programming languages are amazing. You can use them to generate variations, to make things feel spontaneous and fresh. Until now there was no way to create a random number in CSS. Now, the
random()
function is on its way.
Upon first play, it’s great!
This is only in Safari Technical Preview right now. I’ll post videos below so you can see it, and link to live demos.
CSS processors like Sass have been able to do this for ages, but it’s not nearly as nice in that context.
- The
random()
numbers in Sass are only calculated at compile time. So they are only random at the time. Refreshing the page doesn’t mean newly random values. - Random numbers are usually paired with a loop. So if you want 1,000 randomly placed elements, you need 1,000
:nth-child()
selectors with a randomly generated value in each, meaning bulky CSS.
With random()
in vanilla CSS, no such loops are needed and making the code quite simple and satisfying.
I found a 12-year-old Sass demo of mine playing with random()
that is like this:

But now it’s just like this:

Much of the magic, to me, is how each matching element gets its own random values. So if you had three things like this:
<div class="thing"></div>
<div class="thing"></div>
<div class="thing"></div>
Code language: HTML, XML (xml)
Then this simple CSS could make them all quite different:
.thing {
position: absolute;
background: red;
width: 100px;
height: 100px;
top: random(10px, 200px);
left: random(100px, 400px);
background: rgb(
random(0, 255),
random(0, 255),
random(0, 255)
)
}
Code language: CSS (css)
The blog post doesn’t mention “unitless” numbers like I’ve used above for the color, but they work fine. If you’re using units, they need to be the same across all parameters.
The “starfield” demo in the blog post is pretty darn compelling!
I found another old demo where I used a bit of randomized animation-delay
where in the SCSS syntax I did it like this:
animation-delay: (random(10) / 40) + s;
Code language: SCSS (scss)
Notice I had to append the “s” character at the end to get units there. Now in vanilla CSS you just declare the range with the units on it, like:
animation-delay: calc(random(0s, 10s) / 40);
Code language: CSS (css)
And it works great!
The feature does have a spec, and I’m pleased that it has covered many things that I hadn’t considered before but are clearly good ideas. The blog post covers this nicely, but allow me to re-iterate:
.random-rect {
width: random(100px, 200px);
height: random(100px, 200px);
}
Code language: CSS (css)
Both the width
and height
will be different random values. But if you want them to be the same random value, you can set a custom ident value that will “cache” that value for one element:
.random-square {
width: random(--foo, 100px, 200px);
height: random(--foo, 100px, 200px);
}
Code language: CSS (css)
Nice!
But if you had 20 of these elements, how could you make sure all had the same random values? Well there is a special keyword for that, ensuring all matched elements share the same random values:
.shared-random-rect {
width: random(element-shared, 100px, 200px);
height: random(element-shared, 100px, 200px);
}
Code language: CSS (css)
But in that case, all matched elements would share the same random values, but the width
and height
wouldn’t be equal. So you’d do both to make sure it’s all equal:
.shared-random-squares {
width: random(--foo element-shared, 100px, 200px);
height: random(--foo element-shared, 100px, 200px);
}
Code language: CSS (css)
That’s all very nicely considered, I think.
Ranges are also handled with a final parameter:
top: random(10px, 100px, 20px);
transition-delay: random(0s, 5s, 1s);
Code language: HTTP (http)
The top
value above can only be: 10px, 20px, 30px, 40px, 50px, 60px, 70px, 80px, 90px, or 100px.
The transition-delay
value above can only be: 0s, 1s, 2s, 3s, 4s, or 5s.
Otherwise you can get decimal values of either which might be more random than you want. Even 1px
for random pixel values as an increment seems to be suggested.
(Note the WebKit blog has a code sample with by 20deg
in it, which I think is a typo as that doesn’t work for me.)
I didn’t have a chance to try it yet — but doesn’t it make you wanna force a re-render and see if it will work with document.startViewTransition
??