More CSS random() Learning Through Experiments
More CSS random() Learning Through Experiments êŽë š
The random() function in CSS is well-specced and just so damn fun. I had some, ahem, random ideas lately I figured Iâd write up.
Note
As I write, you can only see random() work in Safari Technical Preview. Iâve mostly used videos to show the visual output, as well as linked up the demos in case you have STP.
Rotating Star Field
I was playing this game BALL x PIT which makes use of this rotating background star field motif. See the video, snipped from one of the games promo videos.
I like how the star field is random, but rotates around the center, and in rings where the direction reverses.
My idea for attempting to reproduce it was to make a big stack of <div> containers where the top center of them are all in the exact center of the screen. Then apply:
- A
random()height - A
random()rotation
Then if I put the âstarâ at the end (bottom center) of each <div>, Iâll have a random star field where I can later rotate the container around the center of the screen to get the look I was after.
Making a ton of divs is easy in Pug:
- let n = 0;
- let numberOfStars = 1000;
while n < numberOfStars
- ++n
div.starContainer
div.star
Then the setup CSS is:
.starContainer {
position: absolute;
left: 50%;
top: 50%;
rotate: random(0deg, 360deg);
transform-origin: top center;
display: grid;
width: 4px;
height: calc(1dvh * var(--c));
&:nth-child(-n+500) {
/* Inside Stars */
--rand: random(--distAwayFromCenter, 0, 35);
}
&:nth-child(n+501) {
/* Outside Stars */
--rand: random(--distAwayFromCenter2, 35, 70);
}
}
.star {
place-self: end;
background: red;
height: calc(1dvh * var(--rand));
width: random(2px, 6px);
aspect-ratio: 1;
border-radius: 50%;
}
If I chuck a low-opacity white border on each container so you can see how it works, weâve got a star field going!


Then if we apply some animated rotation to those containers like:
/* ... */
transform-origin: top center;
animation: r 20s infinite linear;
&:nth-child(-n+500) {
/* ... */
--rotation: 360deg;
}
&:nth-child(n+501) {
/* ... */
--rotation: -360deg;
}
@keyframes r {
100% {
rotate: var(--rotation);
}
}
We get the inside stars rotating one way and the outside stars going the other way:
I donât think I got it nearly as cool as the BALL x PIT design, but perhaps the foundation is there.
I found this particular setup really fun to play with, as flipping on and off what CSS you apply to the stars and the containers can yield some really beautiful randomized stuff.
Imagine what you could do playing with colors, shadows, size transitions, etc!
Parallax Stars
While I had the star field thing on my mind, it occurred to me to attach them to a scroll-driven animation rather than just a timed one. I figured if I selected a random selection of 1/3 of them into three groups, I could animate them at different speeds and get a parallax thing going on.
This one is maybe easier conceptually as we just make a bunch of star <div>s (I wonât paste the code as itâs largely the same as the Pug example above, just no containers) then place their top and left values randomly.
.star {
width: random(2px, 5px);
aspect-ratio: 1;
background: white;
position: fixed;
top: calc(random(0dvh, 150dvh) - 25dvh);
left: random(0dvh, 100dvw);
opacity: 0.5;
&:nth-child(-n + 800) {
opacity: 0.7;
}
&:nth-child(-n + 400) {
opacity: 0.6;
}
}
Then attach the stars to a scroll-driven animation off the root.
.star {
/* ... */
animation: move-y;
animation-timeline: scroll(root);
animation-composition: accumulate;
--move-distance: 100px;
opacity: 0.5;
&:nth-child(-n + 800) {
--move-distance: 300px;
opacity: 0.7;
}
&:nth-child(-n + 400) {
--move-distance: 200px;
opacity: 0.6;
}
}
@keyframes move-y {
100% {
top: var(--move-distance);
}
}
So each group of stars either moves their top position 100px, 200px or 300px over the course of scrolling the page.
The real trick here is the animation-composition: accumulate; which is saying not to animate the top position to the new value but to take the position they already have and âaccumulateâ the new value it was given. Leading me to think:
Horizontal Rules of Gridded Dots
Intrigued by combining random() and different animation controlling things, I had the thought to toss steps() into the mix. Like what if a scroll-driven animation wasnât smooth along with the scrolling, it kinda stuttered the movement of things only on a few âframesâ. I considered trying to round() values at first, which is maybe still a possibility somehow, but landed on steps() instead.
The idea here is a ârandomâ grid of dots that then âstepâ into alignment as the page scrolls. Hopefully creating a satisfying sense of alignment when it gets there, half way through the page.
Again Pug is useful for creating a bunch of repetitive elements[1] (but could be JSX or whatever other templating language):
- var numberOfCells = 100;
- var n = 0;
.hr(role="separator")
- n = 0;
while n < numberOfCells
- ++n;
.cell
We can make that <div class="hr" role="seperator"> a flex parent and then randomize some top positions of the cells to look like:

.hr {
view-timeline-name: --hr-timeline;
view-timeline-axis: block;
display: flex;
gap: 1px;
> .cell {
width: 4px;
height: 4px;
flex-shrink: 0;
background: black;
position: relative;
top: calc(random(0px, 60px));
animation-name: center;
animation-timeline: --hr-timeline;
animation-timing-function: steps(5);
animation-range: entry 50% contain 50%;
animation-fill-mode: both;
}
}
Rather than using a scroll scroll-driven animation (lol) weâll name a view-timeline meaning that each one of our separators triggers the animation based on itâs page visibility. Here, it starts when itâs at least half-visible on the bottom of the screen, and finished when itâs exactly half-way across the screen.
Iâll scoot those top positions to a shared value this time, and wait until the last âframeâ to change colors:
@keyframes center {
99% {
background: black;
}
100% {
top: 30px;
background: greenyellow;
}
}
And we get:
Just playing around here. I think random() is an awfully nice addition to CSS, adding a bit of texture to the dynamic web, as it were.
Styling grid cells would be a sweet improvement to CSS in this case! Here where weâre creating hundreds or thousands of divs just to be styleable chunks on a grid, thatâs a lot of extra DOM weight that is really just content-free decoration. â©ïž