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.
| Attribute | Default | Description |
|---|---|---|
data-bg-color | #7c5cfc | Base color applied to all three layers via CSS currentColor. |
data-bg-size | 200 | Shape 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-opacity | 0.6 | Master opacity. Accepts 0-1 (normalized internally to 0-100). Each layer multiplies this by its own factor. |
data-bg-blur | 60 | Gaussian blur radius in pixels. Higher values produce softer, more ambient results. |
data-bg-spread | 80 | Distance between layers. 0 stacks all three at center. Higher values push layers apart relative to container size. |
data-bg-anim | float | Animation preset. See list below. |
data-bg-duration | 6 | Base animation duration in seconds. Each subsequent layer adds 1.5s for natural offset. |
data-bg-easing | ease-in-out | CSS easing function for the animation. |
Animations #
Set data-bg-anim to one of these values. Invalid values fall back to float.
| Name | Effect |
|---|---|
float | Gentle vertical bob with subtle scale |
pulse | Scale in/out with opacity shift |
drift | Wander in x/y with slight rotation |
rotate | Continuous 360° rotation |
breathe | Slow 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 #
| Layer | Hue shift | Brightness | Opacity multiplier | Scale |
|---|---|---|---|---|
| 1 | 0° | 1.00 | 0.90 | 1.15 |
| 2 | +20° | 1.15 | 0.70 | 1.00 |
| 3 | -18° | 0.88 | 0.55 | 0.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.