Rellax Parallax Layers — Free data-rellax-speed Parallax Hero Snippet
Rellax Parallax Layers · Scroll · Plain HTML, CSS & JS · Live preview
Copy & paste
Source Code
<div class="rlx-hero">
<div class="rlx-layer rlx-back" data-rellax-speed="-8"></div>
<div class="rlx-layer rlx-mid" data-rellax-speed="-4">
<div class="rlx-blob rlx-blob-a"></div>
<div class="rlx-blob rlx-blob-b"></div>
</div>
<div class="rlx-layer rlx-front" data-rellax-speed="2">
<h1>Depth, from a single attribute</h1>
<p>Every layer here moves at its own <code>data-rellax-speed</code> as you scroll — Rellax reads the attribute and does the rest.</p>
</div>
</div>
<div class="rlx-spacer"></div>*{box-sizing:border-box;margin:0;padding:0}
body{font-family:system-ui,-apple-system,sans-serif;background:#120a1f;color:#f3ecff}
.rlx-hero{position:relative;height:100vh;overflow:hidden;display:flex;align-items:center;justify-content:center}
.rlx-layer{position:absolute;inset:0}
.rlx-back{background:radial-gradient(ellipse at 50% 30%,#3b1a63 0%,#120a1f 70%)}
.rlx-mid{pointer-events:none}
.rlx-blob{position:absolute;border-radius:50%;filter:blur(50px);opacity:.55}
.rlx-blob-a{width:340px;height:340px;background:#7c3aed;top:12%;left:8%}
.rlx-blob-b{width:280px;height:280px;background:#db2777;bottom:8%;right:10%}
.rlx-front{position:relative;z-index:5;text-align:center;max-width:560px;padding:0 24px}
.rlx-front h1{font-size:clamp(30px,6vw,56px);letter-spacing:-.02em;margin-bottom:16px}
.rlx-front p{color:#c8b8ec;font-size:16px;line-height:1.7}
code{background:rgba(219,39,119,.16);color:#f0abfc;padding:2px 6px;border-radius:5px;font-size:.9em;font-family:ui-monospace,Consolas,monospace}
.rlx-spacer{height:60vh;background:linear-gradient(#120a1f,#0a0614);display:flex;align-items:center;justify-content:center;color:#6b5b8f;font-size:14px}// Rellax scans the DOM for every element carrying data-rellax-speed and
// moves it at a rate proportional to that value on each scroll frame —
// negative values drift slower (feel farther away), positive values move
// faster than the natural scroll (feel closer to the viewer).
const rellax = new Rellax('.rlx-layer', {
speed: -2, // default speed for elements without their own data-rellax-speed
center: false,
round: true, // round pixel values for crisper rendering
vertical: true,
horizontal: false,
});
// Rellax caches element positions on init; if the layout changes (fonts
// loading, images resizing) call refresh() to recalculate offsets.
window.addEventListener('load', () => rellax.refresh());Extend with AI
Take This Snippet Further With AI
The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.
What's included
Features
About this UI Snippet
Rellax Parallax Layers — Depth Through data-rellax-speed Attributes

Rellax is a dependency-free parallax library built around one idea: instead of writing scroll-math for every layer by hand, you tag elements with data-rellax-speed and let the library translate them proportionally as the page scrolls. This snippet builds a three-layer hero — a gradient backdrop, a pair of blurred color blobs, and an anchored content layer — where the entire depth effect is expressed through three attribute values.
Speed as depth
Each .rlx-layer carries a data-rellax-speed value: -8 on the back gradient, -4 on the mid blob layer, and 2 on the front content. Rellax interprets negative speeds as moving slower than natural scroll (so the element appears to lag behind and read as farther away) and positive speeds as moving faster than natural scroll (so the element appears to rush ahead and read as closer to the viewer). This mirrors the same depth logic used in Parallax Hero Section, but where that snippet computes per-layer factors from mouse position in hand-written JavaScript, Rellax computes them from scroll position automatically once you call new Rellax(...).
One constructor call, many layers
new Rellax('.rlx-layer', { speed: -2, center: false, round: true }) is the entire JavaScript integration — Rellax queries every matching element, reads its own data-rellax-speed (falling back to the speed option when absent), and attaches a single shared scroll listener that updates all of them together. Adding a fourth layer means adding a new element with its own data-rellax-speed attribute — no changes to the JS at all.
round: true and performance
Rellax uses transform: translate3d under the hood so layer movement is GPU-composited, and the round: true option rounds computed pixel offsets to whole numbers, which avoids sub-pixel blurring on layers with sharp edges or text. Because there's a single scroll listener shared across every tagged element rather than one listener per layer, the library stays cheap even with many layers on a busy page.
Rellax versus a custom parallax script
Compared to hand-rolling parallax with lerp smoothing (as in Parallax Hero Section), Rellax trades fine-grained control (easing curves, mouse-driven input, device tilt) for simplicity — it's scroll-only, attribute-driven, and requires no per-project math. It's the right tool when you want several elements drifting at different rates purely from scroll position and don't need mouse interactivity.
Customizing it
Adjust each layer's data-rellax-speed to taste (Rellax typically expects values roughly between -10 and 10), add more blobs or shapes as additional layers, or call rellax.refresh() after dynamic content changes so offset calculations stay accurate. Pair this hero with Hero Section copy patterns or a Gradient Progress indicator below the fold.
Step by step
How to Use
- 1Add the Rellax CDN scriptInclude rellax.min.js from the CDN panel.
- 2Paste HTML, CSS, and JSA three-layer hero with a gradient, blobs, and content renders.
- 3Scroll down slowlyThe back layer drifts slower, the front content drifts slightly faster.
- 4Compare layer speedsNotice the blobs and headline separate visually as you scroll.
- 5Change data-rellax-speed valuesIncrease or invert them to intensify or reverse the depth effect.
- 6Add a new layerAdd an element with its own data-rellax-speed — no JS changes needed.
Real-world uses
Common Use Cases
data-rellax-speed attribute, as a lighter alternative to a full parallax hero.translate3d keeping the movement composited off the main thread.new Rellax() call.Got questions?
Frequently Asked Questions
It's a rate relative to normal scroll. A speed of 0 would scroll with the page exactly like any other element. Negative values move the element slower than the page scrolls, so it visually lags behind and reads as farther away; positive values move it faster than the page scrolls, so it visually rushes ahead and reads as closer to the viewer. Rellax typically expects values roughly between -10 and 10 for a natural-looking effect.
The selector passed to new Rellax(selector, options) — '.rlx-layer' in this snippet — is queried once on initialization. Every matching element is then read for its own data-rellax-speed attribute; if an element doesn't have one, it falls back to the speed value in the options object. All matched elements are then updated together on every scroll event via a single shared listener.
Rellax calculates each layer's scroll range based on its position and the document's height at initialization time. If images, web fonts, or other async content change the page's layout height after that initial calculation, the cached offsets can drift out of sync with actual scroll position — calling refresh() recalculates everything against the current, fully-loaded layout.
Rellax works on touch scrolling the same way it works on mouse-wheel scrolling, since it responds to actual scroll position rather than pointer movement — unlike mouse-driven parallax such as Parallax Hero Section. That said, heavy parallax can feel unusual on mobile, so consider reducing speed magnitudes or disabling the effect below a breakpoint for smaller screens.
Install the rellax npm package (or keep the CDN script), import it, and instantiate new Rellax(selector, options) inside a mount effect (useEffect, onMounted, or ngAfterViewInit) after your layered elements have rendered. Keep the data-rellax-speed attributes directly on your JSX/template elements. Call rellax.destroy() in the cleanup function to remove Rellax's scroll listener when the component unmounts.