DEV Community

Cover image for Native Random Values in CSS
Alvaro Montoro
Alvaro Montoro Subscriber

Posted on • Originally published at alvaromontoro.com

Native Random Values in CSS

CSS has always been a deterministic language: given the same input, you get the same output. Every time. But that's about to change with the introduction of two new random functions in CSS.

Note: At the time of writing this article, support for this feature is not widespread (only Safari offers partial support for the random() function from version 26.2). This is a review of the specification and the features that are coming.

This article dives straight into the feature. For a more thorough review —including the history of randomization in CSS, how the feature works, and what it means for CSS as a language—, check out my upcoming article, which complements a conference talk I gave recently.

Let's explore the new functions!

random()

random() returns a random value within a specified range. Its simplest form takes two parameters —a minimum and a maximum value—, and produces a result anywhere within that interval.

For example:

div {
  width: random(200px, 500px);
}

/*
Possible outputs:
- width: 230px;
- width: 417px;
- width: 308.342px;
*/
Enter fullscreen mode Exit fullscreen mode

Notice how the resulting values aren't limited to whole numbers. Anything within the range is valid, including decimals.

Incremental Random

But sometimes we don't want decimals (who enjoys dealing with half‑pixels in a layout?), and the good news is that the function accepts an optional third parameter to define the step or increment applied to the random value.

To do that, we can add a third value at the end of the function. This value indicates the increment steps:

div {
  rotate: random(0deg, 180deg, 10deg);
}

/*
Possible outputs:
- rotate: 120deg;
- rotate: 40deg;
- rotate: 180deg;

Not possible:
- rotate: 5deg;
- rotate: 134deg;
- rotate: 89deg;
*/
Enter fullscreen mode Exit fullscreen mode

The increments will start counting from the min value, which means that sometimes the max value may not be an option. For example, random(100, 200, 30) will return 100, 130, 160, or 190; but not 200 (it cannot be reached in increments of 30 from 100) or 210 (out of bounds).

Sharing Options

Each instance of the random() function will return a different value. But there are situations in which we don't want that to happen. For example, let's pretend aspect-ratio doesn't exist, and we want to create a square by setting a random width and height.

div {
  width: random(10em, 30em);
  height: random(10em, 30em);
}

/*
Possible outputs:
- width: 14em; height: 15em;
- width: 21em; height: 11em;
- width: 17em; height: 27em;
*/
Enter fullscreen mode Exit fullscreen mode

There is a way to share random values within the same rule, element, or even globally. This would be done by adding a new parameter passed as the first in the list that allows value sharing.

It can have different values:

  • auto: the default, it will generate different values for each instance of the random() function. It can be omitted.
     

    div {
      width: random(auto, 100px, 200px);
      height: random(auto, 100px, 200px);
    }
    
    /*
    Using auto: this would be equivalent to calling random() 
    without a sharing option.
    
    Possible result:
    - div.div1 --> width: 125px; height: 198px;
    - div.div2 --> width: 142px; height: 101px;
    */
    


     

  • a dashed identifier (e.g. --w): the value will be shared by the properties within the rule.
     

    div {
      width: random(--d, 100px, 200px);
      height: random(--d, 100px, 200px);
    }
    
    /*
    Using a dashed identifier: All the divs will be squared, because 
    the  generated value is shared by the properties (per element.)
    
    Possible result:
    - div.div1 --> width: 150px; height: 150px;
    - div.div2 --> width: 134px; height: 134px;
    */
    


     

  • the element-shared keyword: it can go by itself or with a dashed identifier, the value will not be shared by the properties within the rule, but it will be shared through elements.
     

    div {
      width: random(element-shared, 100px, 200px);
      height: random(element-shared, 100px, 200px);
    }
    
    /*
    Using element-shared by itself: the generated value will be shared
    by the elments but not by the properties within the element.
    
    Possible result:
    - div.div1 --> width: 150px; height: 134px;
    - div.div2 --> width: 150px; height: 134px;
    */
    
    /*--------------------*/
    
    div {
      width: random(--v element-shared, 100px, 200px);
      height: random(--v element-shared, 100px, 200px);
    }
    
    /*
    Using element-shared along a dashed identifier: the generated value 
    will be shared by properties and elements (same value for all)
    
    Possible result:
    - div.div1 --> width: 128px; height: 128px;
    - div.div2 --> width: 128px; height: 128px;
    */
    


     

  • the fixed keyword with a number id: it specifies a fixed global random identifier. So the value is shared globally.
     

    div {
      width: random(fixed 0.5, 100px, 200px);
      height: random(fixed 0.5, 100px, 200px);
    }
    
    /*
    Using fixed: the generated value is shared by the properties 
    across all elements.
    
    Possible result:
    - div.div1 --> width: 167px; height: 167px;
    - div.div2 --> width: 167px; height: 167px;
    */
    

With this, we have reviewed the different syntax forms and options of the random() function. Next, let's explore the second function introduced as part of the latest draft of the CSS Values and Units Module Level 5 specification.

random-item()

CSS includes properties with discrete values that cannot be expressed as a range. In those cases, random() is not particularly helpful. Instead, we need a function that takes a list of possible values and randomly selects one... and that is exactly what random-item() does.

The random-item() function takes a sharing option and a series of values as parameters, then randomly selects and returns one value from the list:

div {
  display: random-item(--d, block, flex, grid, table);
  opacity: random-item(--o, 0.5, 0.6, 0.75, 0.9, 1);
  background: random-item(--b, red, #00f, conic-gradient(#fff 0 0));
}

/*
Possible outputs:
- display: block; opacity: 0.9; background: #00f;
- display: grid; opacity: 0.6; background: red;
- display: flex; opacity: 0.75; background: red;
*/
Enter fullscreen mode Exit fullscreen mode

One important detail: in random-item(), the sharing variable is not optional, it is required.

As a small curiosity, something some readers may already know, but that I discovered while reviewing this specification (though it likely originates from a different one): CSS allows the use of curly braces ({}) to delimit a list of comma-separated values when that list is used as a single value within a comma-separated list of parameters. Basically, this is only necessary when passing nested lists as parameters:

div {
  font-family: random({ Times, serif }, { Arial, sans-serif }, monospace);
}

/*
Potential outputs:
- Times, serif 
- Arial, sans-serif
- monospace
*/
Enter fullscreen mode Exit fullscreen mode

Conclusion

I hope this article was insightful and that you learned about the upcoming random() and random-item() functions in CSS (already here if you are using Safari). It ended up being longer than expected, but I think it was worth covering all the options and explaining them in detail with examples.

Remember to consider browser support in CSS, caching, sharing, and performance implications when applying these functions in production. Also, think about practical use cases such as random colors, rotations, or spacing, which can enhance the visual experience without JavaScript.

Some may question if adding these functions at this level is a good idea at all. From an architectural point of view, they make sense: this is a layout concern, and it should be handled in the layout layer (CSS) rather than the logic layer (JavaScript), as has been the case so far.

...But more on that in the longer article coming up soon!

Top comments (0)