Skip to main content
Photography of Alvaro Montoro being a doofus
Alvaro Montoro

Lucas's Sidekick

Colorful dice

Native Random Values in CSS

The CSS Working Group has published the Values and Units Module Level 5, which introduces native mechanisms for generating random content using only CSS. This is the tl;dr of a longer article exploring randomness in CSS.

css html webdev javascript

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.

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.

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

Support for CSS native random as of February 2026
Feature Safari Chrome Firefox
random() 26.2 X X
random-item() X X X

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;
*/

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;
*/

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;
*/

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 in the element (they have the same caching key), but not across elements.

    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;
    */
    
    This happens because random() internally generates a base random value between 0 and 1, which is then used to calculate the final result. When multiple random() calls use the same dashed identifier, the browser reuses that same base value, causing their results to be correlated, even if the connection isn't obvious.
  • the element-shared keyword: it can go by itself or with a dashed identifier, the value will shared across the elements, but not the properties within the element (unless a dashed identifier is specified).

    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;
*/

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
*/

As with the random() function, if two random-item() use the same dashed identifier and the same number of items, their results will be correlated. For example, if we have random-item(--a, 1, 2, 3) and random-item(--a, red, green, blue) and the result for the first one is 2 (second element), the result for the second one will be green (second element). This correlation may be convenient if we want to pair features.


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!

Article originally published on