Creating stars using SCSS


4 min read

The thing that inspired this was Kevin Powell doing some CSS art (with SCSS) that included stars. I wondered how to do it. I initially wanted to see how it was done without looking - I knew from Twitter that he'd used Sass math, but that was it. But right at the start I thought "I don't think I can create a random number of stars in CSS." I checked his CodePen and immediately saw in the HTML tab that he'd created divs for the stars. Once I'd established I was right, I was off.

Here's what I did.


When creating stars using JavaScript you don't need any HTML. But as I said above, you need to create the stars:

<div class="star"></div>

I copied and pasted that line 200 times. So there will always be 200 stars. It means on a small screen the sky will be full of stars, but on a big screen it will have hardly any stars.

You can easily adjust the number of stars by pasting more lines or deleting some.

CSS set up

As before we want to set the body to be black and fill the screen and make sure there are no scrollbars.

body {
  height: 100%;

body {
  background-color: black;
  overflow: hidden;


Since we're going to be setting the stars' positions later, we need them to be position relative. And they're all going to be white.

.star {
  position: relative;
  background-color: white;

Now we have the basics of the stars, we can set up the random elements. We want to set them to be a random position, random size and random opacity. To do this we loop through them:

@for $i from 1 through 200 {
  .star:nth-of-type(#{$i}) {

The first line is saying to loop through each number from 1 to 200 inclusive. If I'd used 'to' rather than 'through' then it would loop from 1 to 199 (ie 1 to 200 exclusive).

We have to specify how many stars we have, since it can't tell from the HTML. So if you change the number of stars in the HTML, you also have the change the number here to match.

And then we want to do something different for each star. So we can use nth-of-type where n = $i. Except that the $i needs a bit of interpolation here, which we can do by putting #{} around it.

What I mean by that is that CSS can't cope with $i in this instance. Usually in Sass we use the dollar sign for variables. So if I was to say:

$i: white;

Then I could use it like this:

color: $i;

But we haven't declared $i, we're just using it to count the loop. Writing #{$i} tells CSS that it has to go away and work out what $i is. Then it happily finds it in the loop and establishes it's our counting variable.

So now we're looping through each star we can use Sass random() to give each star different properties:

    top: random(101) - 1 + vh;
    left: random(101) - 1 + vw;
    width: random(2) + px;
    height: random(2) + px;
    opacity: random(50) / 100 + 0.5;

With random(), if you don't put anything in brackets it will give you a random number between 0 and 1. If you do put something in brackets, and it's 1 or greater, it will give you a random integer between 1 and the number given.

To get the top and left values to be between 1 and 100vh/vw we first get a random number between 1 and 101 and subtract 1 from it.

Width and height will either be 1px or 2px, which is fine.

We want opacity to be between 0.5 and 1, because any lower than that will be hard to see. But we can't specify the starting value for the random number. However, we can get there by getting a random number between 1 and 50, dividing it by 100 and then adding 0.5. It will give us a random number between 0.51 and 1, but that's close enough.

How random is random?

Randomness can always be a bit of an 'interesting' topic. When it comes to Sass math, random() is calculated at the point it's converted to CSS. Because CSS can't do randomisation, it has to have a fixed number. It means that refreshing the page will give exactly the same configuration of stars. Although, in CodePen, opening it in a new tab will give a different configuration of stars because at that point it's re-compiling the CSS.

The final code

Here's the whole thing in CodePen.