Save Expand icon

Ron Valstar
front-end developer

Random in CSS

CSS has functions; you can calculate values. Apart from basic adding, subtracting, đividing and multiplying, you can also use max, min and even do trigonomic calculations with sin and cos.

This can be very useful for use in conjunction with CSS properties. You can, for instance, apply a transform: rotate(var(--degrees));, and split those degrees in x- and y-offsets using sin(calc(var(--degrees)/180*pi)).

I've made a small example with these cute little ladybugs, because I detest aphids and their filthy ability to reproduce asexually.
The ladybug is a single element that is rotated by a --degrees property. The coloring is a background with layered radial gradients, where the highlight and shadow are moves by calculating the offset from that --degrees property. The box-shadow uses the same x- and y-offsets.

:root {
  --degrees: 45;
  --lightRadians: -1.1;
}
div {
  --radians: calc(var(--degrees)/180*pi);

  --rdns: calc(var(--radians) + var(--lightRadians));

  --remX: calc(cos(var(--rdns))*1rem);
  --remY: calc(sin(var(--rdns))*-1rem);

  --percX: calc(cos(var(--rdns))*1%);
  --percY: calc(sin(var(--rdns))*-1%);
}

CSS functions can probably be used for more useful things. Unfortunately CSS does not come with randomisation. I've written about about random generators before and they are fairly easy to implement. All you need is a sufficiently large number and a modulo function.

But wait, there is a CSS modulo function, it's in the CSS4 specs. Safari and Firefox support it, but not Chrome.
I've tested in both, but unfortunately calculations do not go high enough for simple PRNG's. These normally make use of divisors starting at 2^31-1 (a Mersenne prime). It works with smaller numbers though, if your seeds don't go too high.
The reason large prime numbers are used as modulo is to get a result that does not repeat (immediately).
Another difficulty is that normally the outcome for a PRNG is used as the seed (or input) in the next calculation, this is impossible in CSS.

Usually the PRNG result is divided by it's modulo to create a range from 0 to 1. We might not have a modulo function in CSS' (in Chrome), but we do have another function that turns any number into one between -1 and 1: the sin function.
This doesn't fly for long because the seemingly irregular results turn regular after a number of iterations. But it's better than nothing.

The following works by giving each 'instance' an index number for seed. Since we will not be using the results as a seed we might as well discard the increment number. We only multiply the seed with a very large number.

:root {
  --rndMult: 9999973;
  --index: 1;
}
div {
  --seed: calc((1 + var(--index))*var(--rndMult));
  --rand: calc(0.5 + 0.5*sin(var(--seed)));
}

Some multiplier values produce quite nice results. But you'll notice the values turn regular after a couple of iterations.
I've used this technique for positioning the dots on the ladybugs, and for colouring.

So randomness in pure CSS is possible, but it requires quite some boilerplate. The values also tend to regularity quite fast, but it is good enough to create simple variation.
All we have to do now is wait for Chrome to implement the CSS mod function, and hope Firefox increases the number size, so we can implement LCG PRNG's.
But to be honest, it's way easier to just use JavaScript.