Have you ever explored the power of grid-auto-flow: dense? When combined with randomly generated values (constrained within a set range), you can use grid-column and grid-row properties to create cool, grid-based art. Let’s dive in!

First, let’s create a base grid structure:

main {
  display: grid;
  grid-auto-flow: dense;
  grid-template-columns: repeat(auto-fill,
 minmax(var(--w, 4cqi), 1fr));
}
Enter fullscreen mode Exit fullscreen mode
  • display: grid: Establishes a CSS grid layout.
  • grid-auto-flow: dense: Automatically fills gaps in the grid by repositioning items to minimize empty spaces.
  • grid-template-columns: Defines a responsive column layout. Here, columns are created automatically to fill the available space (auto-fill), each with a minimum width of --w (defaulting to 4cqi) and a maximum width of 1fr.

At this point, --w is undefined, so the default value (4cqi) is used. Here’s what the initial grid looks like:

Initial grid

Next, we’ll fill the grid with a bunch of <b>-nodes. As we render these with JavaScript, we add 2 variables per node:

  • --gc: Number of columns to span.
  • --gr: Number of rows to span.

Here’s how we generate random values in JavaScript:

const random = (min, max) => 
  Math.random() * (max - min) + min

const column = () => 
`--gc:${Math.floor(random(0, 4))};`

const row = () => 
`--gr:${Math.floor(random(0, 3))};`
Enter fullscreen mode Exit fullscreen mode

In CSS, we apply these custom properties:

b {
  background: oklch(var(--l) var(--c) var(--h) / var(--a));
  grid-column: span var(--gc);
  grid-row: span var(--gr, 1);
}
Enter fullscreen mode Exit fullscreen mode

Let’s also add some random colors in oklch, using a small helper method:

const color = () => `--l:${
  random(0, 100)}%;--c:${
  random(0, 0.5)};--h:${
  random(0, 60)};--a:${
  random(0.2, 1)};`
Enter fullscreen mode Exit fullscreen mode

Now we get:

Dense

Thank you, grid-auto-flow: dense!

To make things more dynamic, let’s add transformations like rotation and scaling:

b {
  rotate: var(--r);
  scale: var(--s);
}
Enter fullscreen mode Exit fullscreen mode

In JavaScript, we generate random transformation values:

const transform = () => 
`--r:${random(-2, 3)}deg;
--s:${random(0.8, 1.2)};`
Enter fullscreen mode Exit fullscreen mode

Let’s check it out:

transform

Fancy! Now, to take it up a notch, let’s add some cool SVG filters.

In JavaScript, we add another small helper method to pick a random filter per <b>-node:

const filter = () =>
  `--url:url(#${
    [
      "pencilTexture",
      "pencilTexture2",
      "pencilTexture3",
      "pencilTexture4",
    ][Math.floor(random(0, 4))]
  });`
Enter fullscreen mode Exit fullscreen mode

This gives us:

Filter

Now, by simply adjusting the --w property and the number of elements, we can generate vastly different artworks:

Thin lines

Or:

Image description

We can also adjust the start- and stop values in the color method:

Colors


Demo

Here’s a Codepen demo. I've added controls below the artwork, so you can easily tweak the properties: