Very Early Playing with random() in CSS

Chris Coyier Chris Coyier on

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.

  1. 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.
  2. 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:

This compiled to over 200 lines of CSS.

But now it’s just like this:

Demo

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)
Demo

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!

Demo

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??

Wanna be a better designer?

Frontend Masters logo

Sarah Drasner is a heck of a designer, and has a wonderful course called Design for Developers where you'll learn to be a self-sufficient designer.

7-Day Free Trial

Leave a Reply

Your email address will not be published. Required fields are marked *

$839,000

Frontend Masters donates to open source projects through thanks.dev and Open Collective, as well as donates to non-profits like The Last Mile, Annie Canons, and Vets Who Code.