Code

CSS

Generative Art with CSS

Pure CSS as a generative-art engine — layers, repetition, transforms, blend modes, and animation. No canvas, no JS rendering loop.

1. Layered Gradients — the CSS "shader"

Stack unlimited radial-gradient or linear-gradient layers on a single element. Each layer is like a brush stroke — overlap them to produce atmospheric, painterly fields.

.art {
  background:
    radial-gradient(circle at 20% 30%, #ff6b6b, transparent 60%),
    radial-gradient(circle at 80% 70%, #4ecdc4, transparent 60%),
    radial-gradient(circle at 50% 50%, #ffe66d, transparent 60%),
    #1a1a1a;
}

2. CSS Variables as "Random Seeds"

Inject randomness with JS once, then let CSS own the rendering. Math.random() sets a custom property; var() drives every visual decision. This gives generative variation without a rendering engine.

/* JS — runs once on load */
document.documentElement.style.setProperty('--x', Math.random() * 100 + '%');
document.documentElement.style.setProperty('--y', Math.random() * 100 + '%');

/* CSS — consumes the variables */
.blob {
  width: 100vw;
  height: 100vh;
  background: radial-gradient(circle at var(--x) var(--y), #ff0080, #000);
}

3. Pseudo-elements as Instances

::before and ::after create two extra shape layers with zero extra HTML. With mix-blend-mode: screen and filter: blur() they interact like light sources.

.art::before,
.art::after {
  content: "";
  position: absolute;
  inset: -20%;
  background: radial-gradient(circle, #ff0080, transparent 60%);
  mix-blend-mode: screen;
  animation: move 20s infinite alternate ease-in-out;
  filter: blur(80px);
}

.art::after {
  background: radial-gradient(circle, #00e5ff, transparent 60%);
  animation-duration: 25s;
}

@keyframes move {
  0%   { transform: translate(-20%, -10%) scale(1); }
  100% { transform: translate(20%, 10%) scale(1.4); }
}

4. Conic Gradient + Rotation

conic-gradient maps colour around a full 360° sweep — great for colour wheels, mandala-like forms, and spinning spectrum effects. Add filter: blur() contrast() to sharpen edges into hard bands.

.spinner {
  width: 160px;
  height: 160px;
  border-radius: 50%;
  background: conic-gradient(
    from 0deg,
    #ff0080, #ffce00, #00e5ff,
    #7c3aed, #ff0080
  );
  animation: spin 6s linear infinite;
  filter: blur(2px) contrast(120%);
}

@keyframes spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

5. Hue-Rotate Aurora

Animate filter: hue-rotate() over stacked radial gradients to cycle all colours on the spectrum over time — a simple one-liner that produces a living, breathing aurora borealis effect.

.aurora {
  background:
    radial-gradient(ellipse at 30% 60%, #a855f7, transparent 55%),
    radial-gradient(ellipse at 70% 40%, #06b6d4, transparent 55%),
    radial-gradient(ellipse at 50% 80%, #10b981, transparent 55%),
    #0a0a0a;
  animation: hue-drift 12s linear infinite;
}

@keyframes hue-drift {
  from { filter: hue-rotate(0deg)   saturate(180%) blur(40px); }
  to   { filter: hue-rotate(360deg) saturate(180%) blur(40px); }
}

6. Box-Shadow Particle Field

A single element can fake hundreds of particles via box-shadow — each shadow entry is an independent "copy" of the element positioned anywhere on the canvas. Generate a large shadow list with JS for thousands of particles.

/* Generate with JS for scale */
const shadows = Array.from({ length: 200 }, () => {
  const x = Math.random() * 100;
  const y = Math.random() * 100;
  const r = Math.floor(Math.random() * 255);
  const g = Math.floor(Math.random() * 255);
  return `${x}vw ${y}vh 4px 2px rgb(${r},${g},255)`;
}).join(',');

el.style.boxShadow = shadows;

@keyframes fall {
  from { transform: translateY(0); }
  to   { transform: translateY(100vh); }
}

7. CSS Noise (Repeating Gradients)

Two repeating-linear-gradient layers at 90° form a grid. Animate a tiny translate jitter and layer with mix-blend-mode: difference for a gritty, analog-video texture.

.noise {
  background:
    repeating-linear-gradient(90deg, #000 0 1px, #111 1px 3px),
    repeating-linear-gradient(0deg,  #000 0 1px, #111 1px 3px);
  mix-blend-mode: difference;
  animation: jitter 0.18s steps(1) infinite;
}

@keyframes jitter {
  0%  { transform: translate(0, 0); }
  25% { transform: translate(1px, -1px); }
  50% { transform: translate(-1px, 1px); }
  75% { transform: translate(1px, 1px); }
}

8. Plasma Field — Stacked Conic Rotations

Layer three oversized conic-gradient divs rotating at different speeds with mix-blend-mode: screen. The colour interference between counter-rotating layers produces an organic plasma effect.

.plasma-a {
  background: conic-gradient(from 0deg, #ff0080, #ffce00, transparent 50%);
  animation: spin-a 8s linear infinite;
  filter: blur(30px);
  mix-blend-mode: screen;
}

.plasma-b {
  background: conic-gradient(from 180deg, #00e5ff, #7c3aed, transparent 50%);
  animation: spin-b 12s linear infinite; /* counter-rotate */
}

.plasma-c {
  background: conic-gradient(from 90deg, #10b981, #f59e0b, transparent 50%);
  animation: spin-a 18s linear infinite;
}

9. Moiré Interference Pattern

Two identical fine-line grids rotated slightly against each other produce moiré fringes — classic optical interference. Animate the rotation and watch the fringes ripple and breathe.

.lines-a, .lines-b {
  position: absolute;
  inset: 0;
}

.lines-a {
  background: repeating-linear-gradient(
    0deg, #000 0 1px, transparent 1px 6px
  );
  animation: rotate-a 3s ease-in-out infinite alternate;
}

.lines-b {
  background: repeating-linear-gradient(
    90deg, #000 0 1px, transparent 1px 6px
  );
  mix-blend-mode: multiply;
  animation: rotate-b 3s ease-in-out infinite alternate;
}
Key takeaway: CSS generative art = repeated patterns (gradients, masks, pseudo-elements) + randomness (CSS variables seeded by JS) + animation (keyframes + transforms + filters).