Art with CSS Grid and SVG filters
Mads Stoumann

Mads Stoumann @madsstoumann

About: I'm a tech director, web developer, graphic designer, musician, blogger, comicbook-geek, LEGO-collector, food lover … as well as husband and father!

Location:
Copenhagen, Denmark
Joined:
Nov 16, 2020

Art with CSS Grid and SVG filters

Publish Date: Dec 7 '24
48 13

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:

Comments 13 total

  • Anna Villarreal
    Anna VillarrealDec 8, 2024

    Thank you for including pictures! XD this is cool.

  • Ravin Rau
    Ravin RauDec 8, 2024

    This is quite an interesting thing to play around with. Imagine you are creating a detective game and you want to have such a scene where you have a pec board with all the evidence and pictures, you can make them in this way.

    Thanks for the write up.

  • GrahamTheDev
    GrahamTheDevDec 8, 2024

    I had a lot of fun playing with the sliders I must say!

    Now I just need a "quirky / playful" project to work on so I can steal it and use it! haha.

    • Mads Stoumann
      Mads StoumannDec 9, 2024

      Maybe a detective game, as Ravin suggested?

  • Daniel Heim
    Daniel HeimDec 11, 2024

    I've been thinking about ways to generate interesting mazes for games, and your post has really inspired me. Thanks!

  • Adam
    AdamDec 18, 2024

    Loving the idea!

  • thetiss
    thetissFeb 28, 2025

    Awesome! thanks

Add comment