Christian Heilmann

Shuffling a CSS grid using custom properties

Monday, November 24th, 2025 at 9:27 am

Recording of the grid shuffling in action

In his excellent talk Get the Core Right and the Resilient Code Will Follow at Beyond Tellerrand in Berlin this year, Andy Bell showed how to sensibly discuss a coding issue amongst your team. He also did a more in-depth write-up on his blog.

The problem that Andy described was having a CSS grid with columns of content next to another and then being asked by the client to randomise the order of the grid on every reload. So that each part of the company will get its 3 seconds in the limelight. Andy is a strong believer in resilient code and rightfully is critical of JavaScript solutions for issues like this. Moving a whole DOM construct like this around can be slow and writing out the whole grid as a component on each interaction can also be iffy.

So I pondered what to do and remembered the CSS order property applying to flex and grid items. Using this one, you can re-order items visually.

<h1>Excellent bands you never heard about</h1>
<ul>
    <li>Irie Revoltes</li>
    <li>Streetlight Manifesto</li>
    <li>Dubioza Kolektiv</li>
    <li>Irish Moutarde</li>
</ul>

If you change the order of the third element to minus one, it shows up first:

ul {
  display: flex;
  flex-direction: column;
  gap: 1em;
}
#dk {
  order: -1;
}

CSS order example

This keeps all the re-ordering work in the CSS engine. But as you can’t as yet have random ordering in CSS, we need some JavaScript to create that functionality. The first idea was to add the order as inline styles, but that would be the same DOM manipulation and having to loop through all items. Instead, I thought about using CSS custom properties:

ul {
  --customorder: -1;
  display: flex;
  flex-direction: column;
}
#dk {
  order: var(--customorder);
}

That way I can access `customorder` on the parent element:

let ul = document.querySelector('ul');
ul.style.setProperty('--customorder',-1);

Putting all of this together, I give you GridShuffle and you can check the code on GitHub:

<div id="contentgrid">
    <div id="about">
        <h2>About</h2>
        This is the order.html file.
    </div>
    <div id="news">
        <h2>News</h2>
        Latest news will be displayed here.
    </div>
    <div id="contact">
        <h2>Contact</h2>
        Contact information will be displayed here.
    </div>  
    <div id="casestudies">
        <h2>Case Studies</h2>
        Case studies will be displayed here.
    </div>
</div>
<button>shuffle</button>

The grid above shuffles around on every reload or when you active `shuffle` button. There are many ways to achieve this effect, but this example uses only CSS properties to set the order of the grid items. The HTML is not altered and there is no DOM manipulation other than accessing the CSS properties of the parent element. This should make this highly performant. The JavaScript code rotates the order of the items in the grid by changing the CSS variables that define their order. Below is the relevant code used to set up the grid and shuffle the items:

#contentgrid {
    --items: 4;
    --item1-order: 1;
    --item2-order: 1;
    --item3-order: 1;
    --item4-order: 1;
    display: grid;
    gap: 20px;
    grid-template-columns: repeat(
        auto-fit, minmax(200px, 1fr)
    );
}
#about { order: var(--item1-order); }
#news { order: var(--item2-order); }
#contact { order: var(--item3-order); }
#casestudies { order: var(--item4-order); }

We define the order of each element as `1`, which means that if we set any of them to `0`, it will be displayed first in the grid. For example, if we did the following, the `Case Studies` section would be displayed first:

#contentgrid {
    --items: 4;
    --item1-order: 1;
    --item2-order: 1;
    --item3-order: 1;
    --item4-order: 0;
/* … */
}
#about { order: var(--item1-order); }
#news { order: var(--item2-order); }
#contact { order: var(--item3-order); }
#casestudies { order: var(--item4-order); }

This could be done on the server-side or with JavaScript as follows:

let root = document.querySelector('#contentgrid');
let itemcount = getComputedStyle(root).
    getPropertyValue('--items');
let old = 1;
const shuffleorder = () => {
    let random = Math.floor(Math.random() * itemcount) + 1;
    root.style.setProperty('--item' + old + '-order', 1);
    root.style.setProperty('--item' + random + '-order', 0);
    old = random;
};
shuffleorder();

We get the amount of items in the grid by reading the value of `—items` CSS property on the root element, and store the current first one in the `old` variable. We then pick a random number between `1` and the total number of items, and set the order of the old item to `1` and the new, random, item to `0`. We then re-define `old` as the new item.

This is the most basic way of doing this, and it is not a real shuffle, as it only rotates the items in a fixed order. You can see the Shuffle Grid example for a more advanced implementation as it randomised the array of all the items. You can also rotate the items by shifting the array of all orders as shown in the Rotate Grid example.

The other examples also don’t need any of the custom properties to be set, but create them instead. This means a tad more JS + DOM interaction but makes the process easier.

let root = document.querySelector('#contentgrid');
let cssvar = `--item$x-order`;
// Get the amount of items
let elms = root.querySelectorAll(
    root.firstElementChild.tagName
);
all = elms.length;
// Initialize the order array and 
// set the order on the items
let orders = [];
for (let i = 1; i &lt;= all; i++) {
    orders.push(i);
    elms[i - 1].style.setProperty(
        'order', 'var(' + cssvar.replace('$x', i) + ')'
    );
    root.style.setProperty(cssvar.replace('$x', i), i);
}

But what if you wanted to not use any JavaScript at all to achieve this? Andy’s solution he showed during the talk was to randomise the order server-side, which is easy to do in many languages. His solution using Jekyll was to generate the page every few minutes, using the sample filter which seems a bit wasteful, but is stable.

Current and future CSS-only solutions

Currently there is no way to randomise or shuffle items using only CSS. However, there are solutions involving Sass which requires pre-processing. Another nifty solution is this way but it requires the use of `@property` which is not widely supported yet.

The CSS spec defines a random() functionality that could be used to achieve this effect without JavaScript. However, as of now, only Safari Technology Preview 170 supports this feature.

Polyfilling CSS isn’t easy, so it might make sense for now to add a dash of JavaScript to your solution to achieve effects like this. This way seems to me a good compromise as it keeps the functionality in CSS instead of shuffling around whole DOM trees or re-writing the whole grid.

Tags: , , , , ,

Share on Mastodon (needs instance)

Share on BlueSky

Newsletter

Check out the Dev Digest Newsletter I write every week for WeAreDevelopers. Latest issues:

160: Graphs and RAGs explained and VS Code extension hacks Graphs and RAG explained, how AI is reshaping UI and work, how to efficiently use Cursor, VS Code extensions security issues.
159: AI pipelines, 10x faster TypeScript, How to interview How to use LLMs to help you write code and how much electricity does that use? Is your API secure? 10x faster TypeScript thanks to Go!
158: 🕹️ Super Mario AI 🔑 API keys in LLMs 🤙🏾 Vibe Coding Why is AI playing Super Mario? How is hallucinating the least of our worries and what are rules for developing Safety Critical Code?
157: CUDA in Python, Gemini Code Assist and back-dooring LLMs We met with a CUDA expert from NVIDIA about the future of hardware, we look at how AI fails and how to play pong on 140 browser tabs.
156: Enterprise dead, all about Bluesky and React moves on! Learn about Bluesky as a platform, how to build a React App and how to speed up SQL. And play an impossible game in the browser.

My other work: