Backgrounds✨ Premium

Interactive Mesh

Interactive mesh gradient: three blurred color spots follow the cursor with CSS easing, over a static radial layer — pure DOM, no canvas.

CSSJSInteractif

You'll get access to the interactive demo with a free account.

This effect is part of Effect.Labs — 811 vanilla effects, some free, some premium. Backgrounds has 50 effects, including 6 free. Explore the category →

3 usage examples

Interactive product hero — Cursor-driven SaaS landing — Interactive Mesh example 1

① Interactive product hero — Cursor-driven SaaS landing

WhenA SaaS tool or creative app landing page opens on a full-screen hero; the visitor moves the mouse while discovering the headline and benefits.
WhyA background that reacts to the pointer in real time immediately signals that the interface is alive and responsive — a key differentiator over a plain static gradient, and the distinctive attribute of this effect versus any passive mesh background.
SettingsContainer 100% width/height of section. Blobs 280 px, blur 55 px, transition 0.45s ease-out. Static radial layer in amber/green to anchor the palette when the cursor is absent or outside the container.
Premium card — Interactive background in a dashboard — Interactive Mesh example 2

② Premium card — Interactive background in a dashboard

WhenA feature or pricing card needs to stand out from other dashboard cards without an external image or video.
WhyAt small scale (320 × 210 px), the effect stays subtle and reactive on hover: the card feels alive without distracting from the content (title, price, CTA).
SettingsBlobs scaled down to 120–140 px, blur 30 px, transition 0.2s ease-out for more immediate response. Adjust colors in the :nth-child rules.
Game start screen — Casual game or interactive demo — Interactive Mesh example 3

③ Game start screen — Casual game or interactive demo

WhenThe start screen of a web game or creative demo awaits the player's first click; the interactive background sets the playful tone before the game even begins.
WhyA background that follows the cursor signals an immersive, playful register exactly where interactivity is expected and valued — never forced, always natural.
SettingsWarm/electric palette: blob 1 rgba(255,60,0,.60), blob 2 rgba(255,200,0,.50), blob 3 rgba(200,0,255,.55). Blobs 280 px, blur 50 px, transition 0.25s ease-out for snappy response.

How it works

The effect uses three <div> elements (.interactive-mesh-blob) positioned absolute with border-radius: 50% and filter: blur(40px). This CSS filter turns each solid colored disc into a diffuse light spot; layered together, the three spots merge into a mesh gradient whose color zones overlap according to the pointer position.

On mousemove, the script computes the cursor position relative to the container, then repositions each blob via style.left and style.top — with a unique offset per blob (dx, dy as fractions of the container's width/height). Each blob orbits the cursor at a different distance, creating a constellation of colors in constant motion.

The smooth glide is entirely handled by the CSS rule transition: left .3s ease-out, top .3s ease-out — no requestAnimationFrame loop needed. The browser interpolates the positions: the ease-out curve gives the tracking an elastic character, responsive at the start of a gesture and smooth at the end.

A fourth static layer, .interactive-mesh-static, is a dual radial-gradient (amber bottom-left, green top-right) with filter: blur(25px), pinned at inset: 0. It anchors the palette and enriches the background even when the cursor is outside the container.

Accessibility

  • prefers-reduced-motion: not implemented in the delivered code — blobs always move on mousemove. For motion-sensitive users, add a guard if (matchMedia('(prefers-reduced-motion: reduce)').matches) return; before attaching the listener.
  • No aria-hidden or role="img" is set on the container. Add aria-hidden="true" if the effect is purely decorative, or role="img" aria-label="…" if it should be announced by screen readers.
  • Interaction is mousemove-only — no keyboard or touch response is defined. On touch-only devices (mobile), blobs stay at their initial CSS positions (static gradient).
  • The span.interactive-mesh-label ('Bougez la souris') is DOM text read by assistive technology; its content will be announced if the container is in the reading flow.
  • filter: blur renders on a composited GPU layer in Chrome, Firefox, and Safari — no notable motor-accessibility impact, but worth watching on low-end devices under CPU load.

Browser compatibility

Requires CSS filter: blur() and mousemove events — supported in all modern browsers. Zero external dependencies, no canvas.

Chrome 76+✓ Full
Firefox 72+✓ Full
Safari 14+✓ Full
Edge 79+✓ Full
Mobile iOS✓ Static (no pointer)
Android Chrome✓ Static (no pointer)

Without <code>filter: blur</code> support (very old browsers), blobs appear as solid color discs — the visual effect differs but no JS error occurs. The <code>interactive-mesh-static</code> layer still renders a coherent background.

The code

HTML structure to paste into your page (CSS + JS available with a premium account):

index.html — structure
<div class="interactive-mesh" id="interactiveMesh">
  <div class="interactive-mesh-blob"></div>
  <div class="interactive-mesh-blob"></div>
  <div class="interactive-mesh-blob"></div>
  <div class="interactive-mesh-static"></div>
  <span class="interactive-mesh-label">Bougez la souris</span>
  <!-- Optional: overlay text/CTA -->
</div>
🔒 Unlock the full code — from €2.99 the first month

Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
.interactive-mesh-blob:nth-child(1) background rgba(255, 0, 128, .6) Color and opacity of the first blob (magenta). Opacity (0.4–0.7) controls blending intensity with the other blobs.
.interactive-mesh-blob:nth-child(2) background rgba(0, 200, 255, .5) Color of the second blob (cyan). Playing warm vs cool between blobs creates a sense of depth.
.interactive-mesh-blob:nth-child(3) background rgba(128, 0, 255, .55) Color of the third blob (violet). To add a blob, duplicate an .interactive-mesh-blob and add its {dx, dy} offset to the JS array.
.interactive-mesh-blob filter blur(40px) Blur intensity per blob. 25 px = sharp saturated spots, 60 px = ultra-diffuse gradient. Higher values increase GPU cost slightly.
.interactive-mesh-blob transition left .3s ease-out, top .3s ease-out Easing duration and curve. 0.15s = immediate shadow-like tracking, 0.6s ease-in-out = lazy floating feel.
offsets (JS array, line 3) [{dx:-0.3,dy:-0.2},{dx:0.1,dy:0.15},{dx:0.25,dy:-0.1}] Per-blob offset from the cursor, as fractions of container width/height. Shrink absolute values for a tight mesh, expand for dramatic spread.
.interactive-mesh-static background radial-gradient(at 10% 80%, rgba(255,200,0,.3) 0, transparent 50%), radial-gradient(at 90% 20%, rgba(0,255,128,.25) 0, transparent 50%) Always-visible static layer. Adjust positions (e.g. at 10% 80%) and colors to anchor a background hue even when the cursor is absent.

FAQ

Entirely via CSS: the blob <div> elements are repositioned with style.left and style.top on every mousemove, and the transition: left .3s ease-out rule delegates interpolation to the browser's CSS engine. The result is as smooth as a RAF animation, without any JS loop.
The delivered code targets getElementById('interactiveMesh') — a single element. For multiple instances, extract the logic into an initMesh(el) function that accepts the container as an argument, then call it once per target element.
No: it only listens to mousemove, which is not fired on pure touch interfaces. On mobile, blobs stay at their initial CSS positions (static gradient). Add a touchmove listener to support touch: read e.touches[0].clientX/Y instead of e.clientX/Y.