Background SVG Shapes

Animated SVG background layer. Drop any SVG shape, control size, blur, color, animation, and spread. Zero front-end footprint when not used.


What it does #

Shapes BG takes a single SVG shape and creates three animated, blurred layers that fill the background of whatever section contains it. Each layer gets a slightly different hue, brightness, and timing offset, producing a rich, organic background effect from one shape.

The SVG inside the component acts as a template only and is never rendered directly. The JS reads it, clones it three times, applies your settings, and positions the layers behind your section content.

No front-end weight. The JS and CSS only load when the component is present on the page. No global styles, no framework, no conflicts.


Basic usage #

Add a Shapes BG component inside any section. It positions itself absolutely to fill that section’s background. Your content goes in the section or a container as normal, not inside the Shapes BG element.

html

<section>

  <!-- Background layer — fills the section -->
  <div class="ek-shapes-bg"
       data-bg-color="#7c5cfc"
       data-bg-size="200"
       data-bg-blur="60"
       data-bg-anim="float">
    <svg viewBox="0 0 100 100">
      <circle cx="50" cy="50" r="50" fill="#000"/>
    </svg>
  </div>

  <!-- Section content — separate from Shapes BG -->
  <div class="container">
    <h2>Your heading</h2>
    <p>Your content here.</p>
  </div>

</section>

The parent section needs position: relative. The CSS handles this automatically via :has(> .ek-shapes-bg), but if your browser support requires it, set it manually on the parent element.


Properties #

All properties are set via data-bg-* attributes on the .ek-shapes-bg element.

AttributeDefaultDescription
data-bg-color#7c5cfcBase color applied to all three layers via CSS currentColor.
data-bg-size200Shape scale from 0 to 400. Maps to 20%-90% of the container diagonal. Lower values produce distinct, visible shapes. Higher values fill the container.
data-bg-opacity0.6Master opacity. Accepts 0-1 (normalized internally to 0-100). Each layer multiplies this by its own factor.
data-bg-blur60Gaussian blur radius in pixels. Higher values produce softer, more ambient results.
data-bg-spread80Distance between layers. 0 stacks all three at center. Higher values push layers apart relative to container size.
data-bg-animfloatAnimation preset. See list below.
data-bg-duration6Base animation duration in seconds. Each subsequent layer adds 1.5s for natural offset.
data-bg-easingease-in-outCSS easing function for the animation.

Animations #

Set data-bg-anim to one of these values. Invalid values fall back to float.

NameEffect
floatGentle vertical bob with subtle scale
pulseScale in/out with opacity shift
driftWander in x/y with slight rotation
rotateContinuous 360° rotation
breatheSlow scale with opacity fade

How it works #

The JS runs as an IIFE. On load, it finds every .ek-shapes-bg element, reads its child SVG as a template, and builds three layer nodes inside a container div. Each layer is a cloned SVG wrapped in a positioned div with its own filter, opacity, and animation delay.

The component uses position: absolute with inset: 0 to fill its parent section. The CSS automatically sets position: relative and isolation: isolate on the parent via :has(), so the layers stay behind the section’s content without any manual setup.

On resize, the existing DOM nodes are repositioned and resized. No nodes are destroyed or recreated. A ResizeObserver with 120ms debounce handles this.

The component respects prefers-reduced-motion: reduce. When active, all animations are disabled. It also listens for runtime changes to this preference.

Layer breakdown #

LayerHue shiftBrightnessOpacity multiplierScale
11.000.901.15
2+20°1.150.701.00
3-18°0.880.550.88

All layers use mix-blend-mode: screen, so they lighten and blend naturally against dark backgrounds. On light backgrounds, adjust opacity and color accordingly.


CSS reference #

The companion stylesheet handles three things: filling the parent section, hiding the template SVG, and auto-setting position: relative on the parent.

css

.ek-shapes-bg {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: -1;
}

.ek-shapes-bg > svg {
  position: absolute;
  width: 0; height: 0;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
}

:has(> .ek-shapes-bg) {
  position: relative;
  isolation: isolate;
}

Tips #

Use low data-bg-size values (50-120) with low blur for distinct, recognizable shapes. Use high values (250-400) with high blur for ambient color washes.

The spread property is relative to the parent section. A spread of 80 on a 400px-wide section looks different than the same value on a 1200px section. Test at your target breakpoints.

For hero sections, drift at 8-12s duration produces subtle movement without distraction. For smaller cards or UI elements, breathe at 4-6s keeps things alive without competing with the content.

Any SVG works as a shape source. Circles and blobs produce soft gradients. Geometric shapes with hard edges create more structured patterns. The blur smooths everything, so even complex SVGs simplify at high blur values.

What are your feelings

Updated on 07/04/2026