What makes a good animated background for a website?

An animated background adds movement behind content without competing with it. Most are pure CSS: gradients moved with @keyframes, mesh gradients built from stacked radial-gradient() layers, SVG noise for grain. Canvas or WebGL is used for water, rain or particles that react to the pointer.

How to choose, performance and accessibility
  • Pick a quiet effect such as Mesh Gradient or Color Breathing Gradient behind text-heavy sections, and keep livelier ones like Pool Caustics, Rain on Glass or Aurora Borealis for heroes and splash screens.
  • Check text contrast over the brightest frame, pause canvas effects when they leave the screen, and show a static fallback for prefers-reduced-motion.
  • Mesh Gradient, Floating Particles, Pool Caustics and Noise Overlay are among the free effects on this page, with their complete code; the rest come with Premium.
Dither & ASCII generator — your photo or logo as a living halftone, retro palettes, animated. Free preview, one-block export. Try it with your logo →

Pool Caustics

The shifting light on a swimming-pool floor — an aqua vein network from dual thresholded feTurbulence (tent function + gamma), continuous SVG offset drift and pointer ripples (glow + expanding rings). Zero canvas, zero libs.

💡 Ideal for: pool residence heroes, spa & wellness landings, 5-star hotels, aquatic cosmetics.

SVG feTurbulence Pointer mix-blend-mode
Effect page →
View source code
HTML
<div class="demo-preview" style="padding:0">
                        <svg xmlns="http://www.w3.org/2000/svg"
       style="position:absolute;width:0;height:0;overflow:hidden;"
       aria-hidden="true">
    <defs>
      <!--
        Filtre caustiques : double turbulence seuillée
        Couche 1 (pcaTurb1) : grandes ondes, 8 octaves, freq basse
        Couche 2 (pcaTurb2) : fines mailles, 5 octaves, freq moyenne
        feComponentTransfer "tente" : isole les crêtes à noise ≈ 0.5
        feGamma exp=4/5   : étrangle les veines (ne restent que les pics)
        feBlend screen    : fusionne les deux couches (intersections = spots lumineux)
        feGaussianBlur    : adoucit légèrement les bords des veines
        feColorMatrix     : teinte aqua-blanc (eau + lumière froide)
        JS anime feOffset dx/dy (sinusoïdal) → dérive naturelle sans saut de seed
      -->
      <filter id="pca-cf" x="-4%" y="-4%" width="108%" height="108%"
              color-interpolation-filters="sRGB">
        <feTurbulence id="pcaTurb1" type="fractalNoise"
          baseFrequency="0.0044 0.0033" numOctaves="8" seed="3"
          result="n1"/>
        <feOffset id="pcaOff1" in="n1" dx="0" dy="0" result="no1"/>
        <feComponentTransfer in="no1" result="t1">
          <feFuncR type="table" tableValues="0 0.10 1 0.10 0"/>
          <feFuncG type="table" tableValues="0 0.10 1 0.10 0"/>
          <feFuncB type="table" tableValues="0 0.10 1 0.10 0"/>
        </feComponentTransfer>
        <feComponentTransfer in="t1" result="s1">
          <feFuncR type="gamma" amplitude="1" exponent="4" offset="0"/>
          <feFuncG type="gamma" amplitude="1" exponent="4" offset="0"/>
          <feFuncB type="gamma" amplitude="1" exponent="4" offset="0"/>
        </feComponentTransfer>

        <feTurbulence id="pcaTurb2" type="fractalNoise"
          baseFrequency="0.0074 0.0058" numOctaves="5" seed="19"
          result="n2"/>
        <feOffset id="pcaOff2" in="n2" dx="0" dy="0" result="no2"/>
        <feComponentTransfer in="no2" result="t2">
          <feFuncR type="table" tableValues="0 0.15 1 0.15 0"/>
          <feFuncG type="table" tableValues="0 0.15 1 0.15 0"/>
          <feFuncB type="table" tableValues="0 0.15 1 0.15 0"/>
        </feComponentTransfer>
        <feComponentTransfer in="t2" result="s2">
          <feFuncR type="gamma" amplitude="1" exponent="5" offset="0"/>
          <feFuncG type="gamma" amplitude="1" exponent="5" offset="0"/>
          <feFuncB type="gamma" amplitude="1" exponent="5" offset="0"/>
        </feComponentTransfer>

        <!-- Fusion des deux couches (screen = sommation additive lumineuse) -->
        <feBlend in="s1" in2="s2" mode="screen" result="merged"/>
        <!-- Légère diffusion pour adoucir les bords de veines -->
        <feGaussianBlur in="merged" stdDeviation="0.42" result="soft"/>
        <!-- Teinte aqua-blanc : matrice réglée pour lumière de piscine -->
        <feColorMatrix in="soft" type="matrix"
          values="0.14 0.05 0.08 0 0.01
                  0.30 0.92 0.24 0 0.06
                  0.34 0.40 0.88 0 0.09
                  0    0    0    1 0"/>
      </filter>
    </defs>
  </svg>
                        <div style="width:100%">
<div class="pca-scene" id="pcaScene"
         role="img"
         aria-label="Caustiques d'eau animées — déplacez la souris pour créer des remous">
      <div class="pca-water" aria-hidden="true"></div>
      <div class="pca-caustic" aria-hidden="true" id="pcaCaustic"></div>
      <div class="pca-glow-layer" aria-hidden="true"></div>
      <div class="pca-pointer-glow" aria-hidden="true" id="pcaGlow"></div>
    </div>
                        </div>
                    </div>
CSS
.demo-preview,
.demo-preview *,
.demo-preview *::before,
.demo-preview *::after {
  box-sizing: border-box
}

.demo-preview {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 300px;
  overflow: hidden;
  position: relative;
  background: rgb(26, 26, 36);
  color: rgb(255, 255, 255);
  font-family: sans-serif;
}

.pca-scene {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: 12px;
  overflow: hidden;
  contain: layout style paint;
  cursor: crosshair;
  -webkit-user-select: none;
  user-select: none;
  isolation: isolate;
}

.pca-water {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse 80% 60% at 58% 32%, #0e5878 0%, transparent 62%),
    radial-gradient(ellipse 55% 45% at 18% 72%, #0a4a3c 0%, transparent 55%),
    radial-gradient(ellipse 40% 35% at 82% 75%, #0b3a58 0%, transparent 50%),
    linear-gradient(175deg, #062a3e 0%, #031d2c 42%, #041f1a 100%);
  transition: background 0.6s ease;
}

.pca-caustic {
  position: absolute;
  inset: 0;
  filter: url(#pca-cf);
  mix-blend-mode: screen;
  opacity: var(--pca-op, 0.58);
  will-change: filter;
  background: #000;
}

.pca-glow-layer {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse 50% 35% at 50% 50%, rgba(80, 200, 210, 0.08) 0%, transparent 70%);
  mix-blend-mode: screen;
  pointer-events: none;
}

.pca-pointer-glow {
  position: absolute;
  left: var(--pca-px, 50%);
  top: var(--pca-py, 50%);
  width: 260px;
  height: 260px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(circle,
      rgba(130, 220, 210, 0.38) 0%,
      rgba(80, 190, 200, 0.12) 40%,
      transparent 68%);
  mix-blend-mode: screen;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.45s ease;
  will-change: transform, opacity;
}

.pca-pointer-glow.pca-active {
  opacity: 1;
}

.pca-pointer-glow::before,
.pca-pointer-glow::after {
  content: '';
  position: absolute;
  inset: 30%;
  border-radius: 50%;
  border: 1px solid rgba(130, 225, 215, 0.60);
  animation: pca-ring 2.4s ease-out infinite;
}

.pca-pointer-glow::after {
  border-color: rgba(100, 210, 230, 0.40);
  animation-delay: -1.2s;
  animation-duration: 2.4s;
}

@supports not (filter: url(#pca-cf)) {
  .pca-caustic {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .pca-pointer-glow {
    display: none;
  }

  .pca-pointer-glow::before,
  .pca-pointer-glow::after {
    animation: none;
  }
}

@media (prefers-reduced-transparency: reduce) {
  .pca-caustic {
    display: none;
  }

  .pca-glow-layer {
    display: none;
  }

  .pca-water {
    background:
      radial-gradient(ellipse 70% 50% at 55% 38%, #0d4c68 0%, transparent 65%),
      #042130;
  }
}

.pca-scene.pca-solid .pca-caustic {
  display: none;
}

.pca-scene.pca-solid .pca-glow-layer {
  display: none;
}

.pca-scene.pca-solid .pca-pointer-glow {
  display: none;
}

.pca-scene.pca-solid .pca-water {
  background:
    radial-gradient(ellipse 70% 50% at 55% 38%, #0d4c68 0%, transparent 65%),
    #042130;
}

.pca-scene.pca-night .pca-water {
  background:
    radial-gradient(ellipse 60% 45% at 42% 44%, #081a38 0%, transparent 60%),
    linear-gradient(180deg, #010c1c 0%, #02101a 100%);
}

.pca-scene.pca-night .pca-caustic {

  filter: url(#pca-cf) hue-rotate(48deg) saturate(0.72);
  opacity: calc(var(--pca-op, 0.58) * 0.7);
}

@keyframes pca-ring {
  0% {
    transform: scale(0.15);
    opacity: 0.9;
  }

  100% {
    transform: scale(4.5);
    opacity: 0;
  }
}
JavaScript
(function() {
  (function() {
    /* fx-0826 — Pool Caustics (gratuit) */
    function initPca() {
      /* fx-0826 */
      (function() {
        'use strict';

        /* ---------- Détection préférences ---------- */
        var reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
        var reduceTrans = window.matchMedia('(prefers-reduced-transparency: reduce)').matches;

        /* ---------- Éléments SVG du filtre (communs aux deux scènes) ---------- */
        var off1 = document.getElementById('pcaOff1');
        var off2 = document.getElementById('pcaOff2');
        var turb1 = document.getElementById('pcaTurb1');
        var turb2 = document.getElementById('pcaTurb2');

        /* ---------- Éléments scène principale ---------- */
        var scene = document.getElementById('pcaScene');
        var glow = document.getElementById('pcaGlow');

        /* ---------- Éléments scène exemple d'usage ---------- */
        var sceneEx = document.getElementById('pcaSceneEx');
        var glowEx = document.getElementById('pcaGlowEx');

        /* ---------- État pointeur (pour chaque scène) ---------- */
        var LERP = 0.08;
        var ptr = {
          x: 0.5,
          y: 0.5,
          tx: 0.5,
          ty: 0.5,
          in: false
        };
        var ptrEx = {
          x: 0.5,
          y: 0.5,
          tx: 0.5,
          ty: 0.5,
          in: false
        };

        /* ---------- Paramètres animation caustiques ---------- */
        /* Fréquences de base des deux couches de turbulence */
        var BF1X = 0.0044,
          BF1Y = 0.0033;
        var BF2X = 0.0074,
          BF2Y = 0.0058;
        /* Amplitude des oscillations de baseFrequency (12% env.) */
        var DAMP = 0.001;
        var DAMP2 = 0.0014;
        /* Amplitude dérive feOffset (px). La turbulence se répète tous les ~120px,
           donc ±35px offre une dérive riche sans revenir trop vite au départ.     */
        var AMP1X = 36,
          AMP1Y = 28;
        var AMP2X = 44,
          AMP2Y = 34;

        var speedMult = 1.0; /* contrôlé par le slider de review */
        var phase = 0,
          lastTs = 0; /* phase accumulée : la vitesse module l'AVANCE, jamais la position (aucun saut) */

        function lerp(a, b, t) {
          return a + (b - a) * t;
        }

        /* Met à jour les custom props de position du glow dans une scène */
        function setGlowPos(glowEl, p) {
          if (!glowEl) return;
          var x = (p.x * 100).toFixed(1) + '%';
          var y = (p.y * 100).toFixed(1) + '%';
          glowEl.style.setProperty('--pca-px', x);
          glowEl.style.setProperty('--pca-py', y);
          if (p.in) {
            glowEl.classList.add('pca-active');
          } else {
            glowEl.classList.remove('pca-active');
          }
        }

        /* ---------- Boucle principale rAF ---------- */
        function tick(ts) {
          if (!lastTs) lastTs = ts;
          var dt = Math.min((ts - lastTs) * 0.001, 0.05);
          lastTs = ts;
          phase += dt * speedMult;

          /* Dérive sinusoïdale des offsets SVG (crée le "courant" des caustiques) */
          if (!reduceMotion && !reduceTrans && off1 && off2) {
            var dx1 = Math.sin(phase * 0.14) * AMP1X + Math.sin(phase * 0.09) * (AMP1X * 0.4);
            var dy1 = Math.cos(phase * 0.11) * AMP1Y + Math.cos(phase * 0.07) * (AMP1Y * 0.35);
            off1.setAttribute('dx', dx1.toFixed(1));
            off1.setAttribute('dy', dy1.toFixed(1));

            var dx2 = Math.sin(phase * 0.19 + 0.8) * AMP2X + Math.sin(phase * 0.13 + 0.4) * (AMP2X * 0.35);
            var dy2 = Math.cos(phase * 0.15 + 1.2) * AMP2Y + Math.cos(phase * 0.10 + 0.9) * (AMP2Y * 0.30);
            off2.setAttribute('dx', dx2.toFixed(1));
            off2.setAttribute('dy', dy2.toFixed(1));

            /* Légère variation de baseFrequency → texture change subtilement au fil du temps */
            var f1x = (BF1X + Math.sin(phase * 0.06) * DAMP).toFixed(5) + ' ';
            var f1y = (BF1Y + Math.cos(phase * 0.05) * (DAMP * 0.8)).toFixed(5);
            turb1 && turb1.setAttribute('baseFrequency', f1x + f1y);

            var f2x = (BF2X + Math.sin(phase * 0.08 + 0.5) * DAMP2).toFixed(5) + ' ';
            var f2y = (BF2Y + Math.cos(phase * 0.07 + 1.1) * (DAMP2 * 0.75)).toFixed(5);
            turb2 && turb2.setAttribute('baseFrequency', f2x + f2y);
          }

          /* Interpolation des positions pointeur */
          if (!reduceMotion) {
            ptr.x = lerp(ptr.x, ptr.tx, LERP);
            ptr.y = lerp(ptr.y, ptr.ty, LERP);
            ptrEx.x = lerp(ptrEx.x, ptrEx.tx, LERP);
            ptrEx.y = lerp(ptrEx.y, ptrEx.ty, LERP);
          }
          if (!reduceTrans) {
            setGlowPos(glow, ptr);
            setGlowPos(glowEx, ptrEx);
          }

          requestAnimationFrame(tick);
        }
        requestAnimationFrame(tick);

        /* Normalise les coordonnées pointeur dans [0,1] relativement à une scène */
        function normPos(e, el) {
          var r = el.getBoundingClientRect();
          return {
            x: Math.max(0, Math.min(1, (e.clientX - r.left) / r.width)),
            y: Math.max(0, Math.min(1, (e.clientY - r.top) / r.height))
          };
        }

        /* Attache les événements pointeur à une scène */
        function bindPointer(sceneEl, ptrState) {
          if (!sceneEl || reduceMotion) return;
          sceneEl.addEventListener('pointermove', function(e) {
            var p = normPos(e, sceneEl);
            ptrState.tx = p.x;
            ptrState.ty = p.y;
            /* Le pointeur ne touche PAS à la vitesse du champ (retour Anthony :
               le boost global secouait tout et fatiguait l'œil). Le remous local
               = glow + anneaux uniquement. */
            ptrState.in = true;
          });
          sceneEl.addEventListener('pointerleave', function() {
            ptrState.in = false;
          });
          sceneEl.addEventListener('touchmove', function(e) {
            e.preventDefault();
          }, {
            passive: false
          });
        }

        bindPointer(scene, ptr);
        bindPointer(sceneEx, ptrEx);

        /* ---- Contrôles de review uniquement (NE PAS copier) ---- */
        var intSlider = document.getElementById('pcaInt');
        var intV = document.getElementById('pcaIntV');
        var speedSlider = document.getElementById('pcaSpeed');
        var speedV = document.getElementById('pcaSpeedV');
        var nightBtn = document.getElementById('pcaNight');
        var a11yBtn = document.getElementById('pcaA11y');

        function allScenes() {
          var s = [scene, sceneEx].filter(Boolean);
          return s;
        }

        if (intSlider) {
          intSlider.addEventListener('input', function() {
            intV.textContent = this.value;
            var v = (+this.value / 100).toFixed(3);
            allScenes().forEach(function(s) {
              s.style.setProperty('--pca-op', v);
            });
          });
        }

        if (speedSlider) {
          speedSlider.addEventListener('input', function() {
            speedV.textContent = this.value;
            speedMult = +this.value / 100;
          });
        }

        if (nightBtn) {
          nightBtn.addEventListener('click', function() {
            var on = false;
            allScenes().forEach(function(s) {
              on = s.classList.toggle('pca-night');
            });
            this.setAttribute('aria-pressed', on ? 'true' : 'false');
          });
        }

        if (a11yBtn) {
          a11yBtn.addEventListener('click', function() {
            var on = false;
            allScenes().forEach(function(s) {
              on = s.classList.toggle('pca-solid');
            });
            this.setAttribute('aria-pressed', on ? 'true' : 'false');
          });
        }

      })();
    }
    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', initPca);
    else initPca();
  })();
})();

Topographic Drift

An fBm noise field discretised into slowly drifting contour lines — the cursor raises a « hill » of concentric rings that follows it (rAF + lerp). 3 palettes (Slate · Teal · Sand), canvas 2D, zero libs.

💡 Ideal for: dev-tools SaaS heroes, analytics dashboards, infra/cloud landings, status pages.

Canvas 2D Contour Lines Pointer Premium

Rain on Glass

Rain on glass in 2D canvas: refracting drops (night-city bokeh flipped and zoomed inside each drop), stick-slip physics, coalescence, and evaporating micro-droplet trails. ≤ 80 drops, DPR handled, zero dependencies.

💡 Ideal for: real-estate or autumn editorial heroes, weather landings, night-time login pages.

Canvas 2D Physics Refraction Premium

Ink Bloom

Watercolour blooms open with organic fractal edges (feTurbulence + dual feDisplacementMap) and layer into mixed pigments (multiply on cream paper, screen on dark). Edges keep breathing after the bloom; click blooms at the clicked point.

💡 Ideal for: gallery or portfolio heroes, creative landings, editorial covers, luxury sections.

feTurbulence feDisplacementMap Click Premium

Storm Veil

Procedural 2D canvas storm: branching lightning via midpoint displacement (3-pass halo→body→core render), parallax clouds, optional fine rain, soft capped flash (a11y, never a strobe). Every strike is unique; click strikes where you click.

💡 Ideal for: dramatic launch heroes, game landing pages, high-stakes teasers.

Canvas 2D Procedural Click Premium
Mesh

Mesh Gradient

Multiple radial gradients that slowly shift positions.

CSS Gradient Organic
Effect page →
View source code
HTML
<div class="demo-preview bg-mesh">
  <span class="bg-label">Mesh</span>
</div>
CSS
.demo-preview,
.demo-preview *,
.demo-preview *::before,
.demo-preview *::after {
  box-sizing: border-box
}

.demo-preview {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 300px;
  overflow: hidden;
  position: relative;
  background: rgb(10, 10, 15);
  color: rgb(255, 255, 255);
  font-family: sans-serif;
}

.demo-preview.bg-mesh {
  background:
    radial-gradient(at 40% 20%, #6366f1 0px, transparent 50%),
    radial-gradient(at 80% 0%, #d946ef 0px, transparent 50%),
    radial-gradient(at 0% 50%, #06b6d4 0px, transparent 50%),
    radial-gradient(at 80% 50%, #8b5cf6 0px, transparent 50%),
    radial-gradient(at 0% 100%, #6366f1 0px, transparent 50%),
    radial-gradient(at 80% 100%, #f43f5e 0px, transparent 50%);
  background-color: #0a0a0f;
  animation: meshMove 20s ease infinite;
}

.bg-label {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-weight: 700;
  font-size: 1.5rem;
  color: white;
  text-shadow: 0 2px 10px rgba(0, 0, 0, 0.5);
  z-index: 10;
}

@keyframes meshMove {

  0%,
  100% {
    background-position: 0% 0%, 100% 0%, 0% 100%, 100% 50%, 0% 100%, 100% 100%;
  }

  50% {
    background-position: 100% 100%, 0% 100%, 100% 0%, 0% 50%, 100% 0%, 0% 0%;
  }
}
JavaScript
/* Pure CSS — no JavaScript required */
Particles

Floating Particles

Particles that continuously float upward.

JS Particles Loop
Effect page →
View source code
HTML
<div class="bg-particles" id="particlesBg" style="width:100%;min-height:300px;">
  <span class="bg-label">Particles</span>
</div>
CSS
.bg-particles  {
   position: relative;
   overflow: hidden;
   background: rgb(10, 10, 15);
   }

.particle  {
   position: absolute;
   bottom: -20px;
   width: 4px;
   height: 4px;
   background: rgb(99, 102, 241);
   border-radius: 50%;
   animation: 10s ease 0s infinite normal none running float;
   }

@keyframes float  {
   
  0%  {
   transform: translateY(0px) rotate(0deg);
   opacity: 0;
   }
  10%  {
   opacity: 1;
   }
  90%  {
   opacity: 1;
   }
  100%  {
   transform: translateY(-350px) rotate(720deg);
   opacity: 0;
   }
}

.bg-label  {
   position: absolute;
   top: 50%;
   left: 50%;
   transform: translate(-50%, -50%);
   font-weight: 700;
   font-size: 1.5rem;
   color: white;
   text-shadow: rgba(0, 0, 0, 0.5) 0px 2px 10px;
   z-index: 10;
   }
JavaScript
// Generate particles
    (function() {
      var el = document.getElementById('particlesBg');
      if (!el) return;
      var colors = ['#6366f1', '#8b5cf6', '#d946ef', '#06b6d4'];
      for (var i = 0; i < 30; i++) {
        var particle = document.createElement('div');
        particle.className = 'particle';
        particle.style.left = Math.random() * 100 + '%';
        particle.style.animationDelay = Math.random() * 10 + 's';
        particle.style.animationDuration = (5 + Math.random() * 10) + 's';
        particle.style.width = (2 + Math.random() * 4) + 'px';
        particle.style.height = particle.style.width;
        particle.style.opacity = 0.3 + Math.random() * 0.7;
        particle.style.background = colors[Math.floor(Math.random() * colors.length)];
        el.appendChild(particle);
      }
    })();

Gradient Wave

Diagonal gradient animated in a smooth loop.

CSS Gradient Smooth

Aurora Borealis

Northern lights effect with dancing lights.

CSS Aurora Blur

Grid Pattern

Technical grid with center vignette.

CSS Pattern Tech

Noise Texture

Grain texture for a cinematic look.

CSS Texture Film

Light Rays

Light rays in continuous rotation.

CSS Light Rotate

Animated Blobs

Floating organic shapes with blur.

CSS Organic Blur

Geometric Shapes

Animated floating geometric shapes.

CSS Shapes Float

Starry Night

Twinkling starry sky with shooting stars.

JS Stars Night

Aurora Effect

Northern lights effect with animated colorful gradients.

CSS Aurora Animated

Noise/Grain Texture

Grainy SVG texture for a cinematic effect.

CSS SVG Texture

Animated Mesh Gradient

Animated mesh gradient with smooth transitions.

CSS Gradient Animated

Star Field

Star field in continuous motion.

CSS Stars Space

Gradient Animation Loop

Multicolor gradient in an infinite loop.

CSS Gradient Loop

Network Lines

Geometric connected network lines.

CSS Pattern Tech

Holographic Effect

Holographic effect with rainbow colors.

CSS Holographic Rainbow

Dot Grid Pattern

Elegant and minimalist dot grid.

CSS Pattern Minimal

Floating Shapes

Colorful floating shapes with blur effect.

CSS Shapes Blur

Spotlight Follow

Spotlight that follows the mouse cursor.

CSS JS Interactive
AURORA

Aurora Mesh

Aurora borealis mesh with green, cyan and purple gradients that blend and slowly ripple.

CSS Animation Organic
Effect page →
View source code
HTML
<div class="demo-preview">
  <div class="aurora-mesh">
    <span class="aurora-mesh-label">AURORA</span>
  </div>
</div>
CSS
.demo-preview,
.demo-preview *,
.demo-preview *::before,
.demo-preview *::after {
  box-sizing: border-box
}

.demo-preview {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 300px;
  overflow: hidden;
  position: relative;
  background: rgb(26, 26, 36);
  color: rgb(255, 255, 255);
  font-family: sans-serif;
}

.aurora-mesh {
  width: 320px;
  height: 220px;
  border-radius: 16px;
  position: relative;
  overflow: hidden;
  background: #0a0a0f;
}

.aurora-mesh::before {
  content: '';
  position: absolute;
  inset: -20%;
  background:
    radial-gradient(ellipse at 25% 30%, rgba(0, 255, 128, 0.6) 0%, transparent 50%),
    radial-gradient(ellipse at 70% 20%, rgba(0, 220, 255, 0.5) 0%, transparent 50%),
    radial-gradient(ellipse at 50% 70%, rgba(160, 0, 255, 0.5) 0%, transparent 50%),
    radial-gradient(ellipse at 15% 80%, rgba(0, 180, 200, 0.4) 0%, transparent 50%),
    radial-gradient(ellipse at 85% 60%, rgba(0, 255, 180, 0.35) 0%, transparent 50%);
  filter: blur(30px);
  animation: auroraDrift 8s ease-in-out infinite alternate;
}

.aurora-mesh::after {
  content: '';
  position: absolute;
  inset: -20%;
  background:
    radial-gradient(ellipse at 60% 40%, rgba(80, 255, 200, 0.4) 0%, transparent 45%),
    radial-gradient(ellipse at 20% 60%, rgba(0, 200, 255, 0.35) 0%, transparent 45%),
    radial-gradient(ellipse at 80% 80%, rgba(120, 0, 255, 0.4) 0%, transparent 45%);
  filter: blur(25px);
  animation: auroraDrift2 10s ease-in-out infinite alternate;
}

.aurora-mesh-label {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 800;
  font-size: 1.3rem;
  letter-spacing: 3px;
  color: rgba(255, 255, 255, 0.9);
  text-shadow: 0 0 20px rgba(0, 255, 180, 0.5);
}

@keyframes auroraDrift {
  0% {
    transform: translate(0, 0) scale(1) rotate(0deg);
  }

  33% {
    transform: translate(5%, -8%) scale(1.05) rotate(2deg);
  }

  66% {
    transform: translate(-5%, 5%) scale(0.95) rotate(-2deg);
  }

  100% {
    transform: translate(8%, -3%) scale(1.02) rotate(1deg);
  }
}

@keyframes auroraDrift2 {
  0% {
    transform: translate(0, 0) scale(1) rotate(0deg);
  }

  50% {
    transform: translate(-8%, 6%) scale(1.08) rotate(-3deg);
  }

  100% {
    transform: translate(6%, -6%) scale(0.96) rotate(2deg);
  }
}
JavaScript
/* Pure CSS — no JavaScript required */

Sunset Mesh

Warm-toned sunset mesh gradient — orange, pink, red and purple in motion.

CSS Animation Warm

Neon Mesh

Vibrant neon mesh with pulsating spots of electric blue, hot pink and lime green.

CSS Neon Vibrant

Pastel Mesh

Soft mesh gradient with lavender, mint and peach tones floating in harmony.

CSS Soft Pastel

Monochrome Mesh

Elegant monochrome mesh in shades of blue and indigo, subtle and deep.

CSS Monochrome Elegant

Interactive Mesh

Interactive mesh gradient whose color spots follow the mouse cursor.

CSS JS Interactif

Gradient Morph

The mesh morphs between two completely different color palettes every few seconds.

CSS JS Transition

Noise Mesh

Mesh gradient overlaid with a subtle SVG noise texture for an organic, textured look.

CSS SVG Texture

Glass Mesh Card

Card with colorful mesh background and glassmorphism overlay with blur and transparency.

CSS Glass Composant

Animated Border Mesh

Animated border made of a multicolor mesh gradient rotating around the element.

CSS Border Animation
Breathing Gradient

Color Breathing Gradient

Breathing gradient animating angle and hues via @property in OKLCH color space.

CSS @property OKLCH
Effect page →
View source code
HTML
<div class="demo-preview">
  <div class="chroma-demo breathing-gradient">
    <span class="label">Breathing Gradient</span>
  </div>
</div>
CSS
.demo-preview,
.demo-preview *,
.demo-preview *::before,
.demo-preview *::after {
  box-sizing: border-box
}

.demo-preview {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 300px;
  overflow: hidden;
  position: relative;
  background: rgb(26, 26, 36);
  color: rgb(255, 255, 255);
  font-family: sans-serif;
}

@property --hue-angle {
  syntax: '<angle>';
  initial-value: 0deg;
  inherits: false;
}

.chroma-demo {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 200px;
  border-radius: 8px;
  overflow: hidden;
  position: relative;
}

.breathing-gradient {
  background: linear-gradient(var(--hue-angle),
      oklch(0.65 0.25 0),
      oklch(0.55 0.28 120),
      oklch(0.7 0.22 240),
      oklch(0.6 0.3 360));
  background-size: 300% 300%;
  animation: breathingHue 8s ease-in-out infinite, breathingAngle 12s linear infinite;
}

.breathing-gradient .label {
  color: white;
  font-weight: 700;
  font-size: 1.1rem;
  text-shadow: 0 2px 8px rgba(0, 0, 0, 0.4);
  letter-spacing: 0.05em;
  z-index: 1;
}

@keyframes breathingHue {

  0%,
  100% {
    background-position: 0% 50%;
  }

  25% {
    background-position: 100% 0%;
  }

  50% {
    background-position: 100% 100%;
  }

  75% {
    background-position: 0% 100%;
  }
}

@keyframes breathingAngle {
  from {
    --hue-angle: 0deg;
  }

  to {
    --hue-angle: 360deg;
  }
}
JavaScript
/* Pure CSS — no JavaScript required */

Duotone Image Filter

Transforms content to duotone on hover using mix-blend-mode and grayscale.

CSS Blend Mode Filter

Halftone Effect

SVG filter with feComponentTransfer and feMorphology for an animated halftone pattern on hover.

SVG Filter Hover Halftone

Chromatic Aberration Text

RGB channel separation on hover creating a prismatic effect with pseudo-elements.

CSS Hover RGB Split

Color Mix Crossfade

Two colors blended via color-mix() showing oklch vs srgb blending paths.

CSS color-mix() OKLCH
Pink
Cyan
Neon

Neon Glow Pulse

Elements with pulsing neon glow via multiple animated box-shadow layers.

CSS Animation Neon
Effect page →
View source code
HTML
<div class="demo-preview">
  <div class="chroma-demo neon-glow-container">
    <div class="neon-element neon-pink">Pink</div>
    <div class="neon-element neon-cyan">Cyan</div>
    <div class="neon-element neon-green">Neon</div>
  </div>
</div>
CSS
.demo-preview,
.demo-preview *,
.demo-preview *::before,
.demo-preview *::after {
  box-sizing: border-box
}

.demo-preview {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 300px;
  overflow: hidden;
  position: relative;
  background: rgb(26, 26, 36);
  color: rgb(255, 255, 255);
  font-family: sans-serif;
}

.chroma-demo {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 200px;
  border-radius: 8px;
  overflow: hidden;
  position: relative;
}

.neon-glow-container {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 20px;
  background: #0a0a0f;
  flex-wrap: wrap;
  padding: 24px;
}

.neon-element {
  padding: 12px 24px;
  border-radius: 12px;
  font-weight: 700;
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  position: relative;
}

.neon-pink {
  color: #ff2d95;
  border: 2px solid #ff2d95;
  text-shadow: 0 0 10px #ff2d95, 0 0 20px #ff2d95;
  animation: neonPulsePink 2s ease-in-out infinite;
}

.neon-cyan {
  color: #00f0ff;
  border: 2px solid #00f0ff;
  text-shadow: 0 0 10px #00f0ff, 0 0 20px #00f0ff;
  animation: neonPulseCyan 2.5s ease-in-out infinite;
}

.neon-green {
  color: #39ff14;
  border: 2px solid #39ff14;
  text-shadow: 0 0 10px #39ff14, 0 0 20px #39ff14;
  animation: neonPulseGreen 3s ease-in-out infinite;
}

@keyframes neonPulsePink {

  0%,
  100% {
    box-shadow: 0 0 5px #ff2d95, 0 0 10px #ff2d95, 0 0 20px #ff2d95, inset 0 0 10px rgba(255, 45, 149, 0.1);
  }

  50% {
    box-shadow: 0 0 10px #ff2d95, 0 0 25px #ff2d95, 0 0 50px #ff2d95, 0 0 80px #ff2d95, inset 0 0 20px rgba(255, 45, 149, 0.15);
  }
}

@keyframes neonPulseCyan {

  0%,
  100% {
    box-shadow: 0 0 5px #00f0ff, 0 0 10px #00f0ff, 0 0 20px #00f0ff, inset 0 0 10px rgba(0, 240, 255, 0.1);
  }

  50% {
    box-shadow: 0 0 10px #00f0ff, 0 0 25px #00f0ff, 0 0 50px #00f0ff, 0 0 80px #00f0ff, inset 0 0 20px rgba(0, 240, 255, 0.15);
  }
}

@keyframes neonPulseGreen {

  0%,
  100% {
    box-shadow: 0 0 5px #39ff14, 0 0 10px #39ff14, 0 0 20px #39ff14, inset 0 0 10px rgba(57, 255, 20, 0.1);
  }

  50% {
    box-shadow: 0 0 10px #39ff14, 0 0 25px #39ff14, 0 0 50px #39ff14, 0 0 80px #39ff14, inset 0 0 20px rgba(57, 255, 20, 0.15);
  }
}
JavaScript
/* Pure CSS — no JavaScript required */

Gradient Spotlight

Radial gradient follows the cursor revealing vibrant colors under a muted surface.

JS Mouse Mask

Thermal Vision

Heat map with hot/cold zones that react to hover interaction.

CSS Hover Gradient

Color Space Morph

Gradient transitioning between sRGB vs OKLCH color spaces showing midpoint differences.

CSS Color Spaces Gradient

Relative Color Palette

Entire palette derived from a single base color via OKLCH and computed custom properties.

CSS JS OKLCH

Noise Overlay

Subtle texture on gradient

Noise Overlay

SVG noise overlay on a gradient background, using mix-blend-mode overlay for a subtle organic texture.

CSS SVG Texture
Effect page →
View source code
HTML
<div class="demo-preview">
  <div class="ng-overlay-scene">
    <div class="ng-overlay-content">
      <h3>Noise Overlay</h3>
      <p>Subtle texture on gradient</p>
    </div>
  </div>
</div>
CSS
.demo-preview,
.demo-preview *,
.demo-preview *::before,
.demo-preview *::after {
  box-sizing: border-box
}

.demo-preview {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 300px;
  overflow: hidden;
  position: relative;
  background: rgb(26, 26, 36);
  color: rgb(255, 255, 255);
  font-family: sans-serif;
}

.ng-overlay-scene {
  width: 320px;
  height: 220px;
  position: relative;
  border-radius: 16px;
  overflow: hidden;
  background: linear-gradient(135deg, #8b5cf6, #ec4899);
}

.ng-overlay-scene::after {
  content: '';
  position: absolute;
  inset: 0;
  background: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  opacity: 0.15;
  mix-blend-mode: overlay;
  pointer-events: none;
}

.ng-overlay-content {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
}

.ng-overlay-content h3 {
  font-size: 1.3rem;
  font-weight: 800;
  color: #fff;
  margin: 0;
}

.ng-overlay-content p {
  font-size: 0.82rem;
  color: rgba(255, 255, 255, 0.8);
  margin: 0;
}
JavaScript
/* Pure CSS — no JavaScript required */

Film Grain

Film effect with animated grain via feTurbulence, horizontal scanlines and dark vignette.

SVG Animation Film

Paper Texture

Paper background with fractalNoise texture in multiply. Parchment look with decorative stamp.

CSS SVG Vintage

Grain Gradient

Dark gradient with animated grain via Canvas 2D. Noise is regenerated each frame for a living effect.

Canvas JS Gradient

Noise Displacement

Text distorted with SVG feDisplacementMap. Distortion intensity increases on hover.

SVG Filter Hover

Frosted Noise

Frosted glass card with backdrop-filter and grain noise overlay layer for a realistic look.

CSS Backdrop Grain

Halftone Pattern

Print halftone effect with dot pattern generated in CSS via repeated radial-gradient.

CSS Pattern Print

Organic Blob

Organic shape with animated SVG feDisplacementMap. The blob naturally deforms with a grain texture.

SVG Animation Organic

Vintage Photo

Retro photo effect with sepia tones, fractal grain, vignette and vintage color overlay.

CSS SVG Retro

Noise Morph

Rotating shape with animated grain and pulsing glow. Multiple noise layers in overlay.

CSS SVG Animation

String Lights

Christmas string lights in SVG: a wire that hangs and sways, colourful bulbs that twinkle, and a soft physics that follows the cursor. Colours, density and text are customisable.

💡 Great for: year-end hero/header, festive banner, greeting card, seasonal landing page, decorated footer.

SVG Vanilla JS Festive Premium

Frequently Asked Questions

How do you animate a background gradient in CSS? +

Set a background with linear-gradient, double its size with background-size: 200% 200%, then animate background-position from 0% 0% to 100% 100% with @keyframes. Add animation: gradient 5s ease infinite for a smooth loop.

Which animated background is the most performant? +

Animated CSS gradients are the lightest as they don't require JavaScript. Canvas particle effects are more demanding but can be optimized by limiting the number of particles and using requestAnimationFrame.

How do you create a wave effect in pure CSS? +

Use an SVG or pseudo-element with animated border-radius. The modern technique uses clip-path with an animated Bezier curve or an SVG path animated with CSS.

How do you prevent an animated background from slowing down your site? +

Use will-change:transform, limit particles to 50-100 max, pause the animation when the element is not visible (IntersectionObserver), and respect prefers-reduced-motion for sensitive users.

Can you use an animated background on mobile? +

Yes, but keep it simple: reduce the number of particles, use CSS gradients instead of canvas, and disable heavy animations on less powerful devices with a resolution media query.

Similar Categories