Multi-Layer Scroll Parallax Banner — Free HTML CSS JS Snippet

Multi-Layer Scroll Parallax Banner · Scroll · Plain HTML, CSS & JS · Live preview

What's included

Features

Three background/foreground layers each moving at an independently configurable scroll rate
Scroll handler strictly limited to reading scrollTop — zero layout work inside the raw event
All getBoundingClientRect() reads and transform writes deferred to a single requestAnimationFrame callback
Frame-coalescing "ticking" flag prevents redundant rAF calls when many scroll events fire per frame
Passive scroll listener for smoother native scrolling performance
Self-contained scrollable demo container with spacer sections for an isolated live preview
translate3d transforms for GPU-accelerated layer movement
Fully configurable per-layer parallax rate via a simple data-rate attribute

About this UI Snippet

Multi-Layer Scroll Parallax Banner — rAF-Throttled Depth Effect on Scroll

Screenshot of the Multi-Layer Scroll Parallax Banner snippet rendered live

This snippet implements the classic scroll-parallax technique: as the user scrolls past a banner, its background layers move vertically at different rates than the foreground content, producing a sense of depth. It's built with performance as the primary concern, since scroll parallax is one of the easiest effects to make janky if done carelessly.

Three layers, three rates

.sb-parallax-layer-back, -mid, and -front each carry a data-rate attribute (0.2, 0.45, and 0.8 respectively). A rate closer to 0 makes a layer move almost independently of scroll (appearing to hang back, like a distant sky), while a rate closer to 1 makes a layer scroll almost in lockstep with the page (appearing close to the viewer) — this is the inverse relationship real parallax depth relies on.

Never reading layout inside the scroll event

The onScroll handler itself does almost nothing: it just records the container's scrollTop and, if a frame isn't already queued, schedules requestAnimationFrame(applyParallax). All the expensive work — calling getBoundingClientRect() (a layout read) and writing transform styles — happens exclusively inside applyParallax(), which only ever runs once per animation frame no matter how many scroll events fire in between. This is the standard fix for scroll-jank: scroll events can fire dozens of times per frame, but layout reads and style writes should only ever happen once per frame.

Computing each layer's offset

applyParallax() measures the banner's position relative to the scrollable container using getBoundingClientRect(), then for each layer computes translateY = offsetWithinArea * (1 - rate) * -1. As the banner scrolls upward (offset becomes more negative), a layer with a low rate lags behind more, while a layer with a rate near 1 tracks almost exactly with the scroll — producing the layered depth effect.

A self-contained scrollable demo area

Because this snippet needs to demonstrate a scroll effect in an isolated preview, the whole example lives inside its own scrollable .sb-scroll-area container with spacer sections above and below the banner, rather than relying on the full page's scroll — the same rAF-throttling technique applies identically to window scroll in a real page by swapping the scroll listener target.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Hand this snippet's HTML, CSS, and JavaScript to an AI coding assistant like Claude and ask it to adapt "Multi-Layer Scroll Parallax Banner" to your project — restyle it to match your design system, wire it up to real data instead of the static example, or port it to the framework you're building in.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a scroll component called "Multi-Layer Scroll Parallax Banner" using plain HTML, CSS, and vanilla JavaScript — no framework, no build step.

Requirements:
- Match the structure and behavior of the "Multi-Layer Scroll Parallax Banner" snippet from the UI Snippets Library.
- Keep the markup semantic and the styling self-contained (no external dependencies beyond what the original snippet uses).
- Keep the JavaScript vanilla, with no framework runtime required.
- Make it easy to restyle via CSS custom properties or class overrides so it can be dropped into a real project.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Source Code

<div class="sb-scroll-area" id="sbScrollArea">
  <div class="sb-spacer sb-spacer-top">
    <p>Scroll down ↓</p>
  </div>

  <section class="sb-banner" id="sbBanner">
    <div class="parallax-layer sb-parallax-layer-back" data-rate="0.2"></div>
    <div class="parallax-layer sb-parallax-layer-mid" data-rate="0.45"></div>
    <div class="parallax-layer sb-parallax-layer-front" data-rate="0.8">
      <h2>Depth in Motion</h2>
      <p>A multi-layer scroll parallax banner</p>
    </div>
  </section>

  <div class="sb-spacer sb-spacer-bottom">
    <p>Keep scrolling</p>
  </div>
</div>

Step by step

How to Use

  1. 1
    Load the snippetClick "Multi-Layer Scroll Parallax Banner" in the sidebar to load its HTML, CSS, and JS into the editor panels. The preview updates instantly.
  2. 2
    Edit the codeModify any panel — HTML, CSS, or JS. The preview refreshes as you type. Use Reset in each panel header to restore the original.
  3. 3
    Preview on devicesClick the Mobile (375px), Tablet (768px), or Desktop buttons in the preview header to check responsiveness.
  4. 4
    Export in your formatClick "HTML" to download a standalone file, "JSX" for a React component, "Tailwind" for a React + Tailwind CSS component, "Tailwind HTML" for a standalone HTML file with Tailwind CDN, "Vue" for a Vue 3 SFC with <template>/<script setup>/<style scoped>, or "Angular" for a standalone Angular .component.ts file. "Copy all" copies the full code to clipboard.
  5. 5
    Save your versionClick "Save as", type a name, and press Enter. Your snippet saves to IndexedDB and appears in the Saved tab.

Real-world uses

Common Use Cases

Marketing and landing page banners
A visually rich section break that adds depth without heavy scroll-jank.
Scroll performance tutorials
A textbook example of the rAF-throttled scroll handler pattern applied to a real effect.
Storytelling and editorial pages
Layered scroll depth for narrative sections between article content.
Reference implementation for scroll listeners
A reusable pattern for any effect that must react to scroll without causing jank.

Got questions?

Frequently Asked Questions

The browser can fire many scroll events within a single animation frame, and reading layout (getBoundingClientRect) inside each one forces repeated synchronous layout recalculation, causing visible jank. Deferring the actual read/write work to a single requestAnimationFrame callback per frame — regardless of how many scroll events fired — keeps the effect smooth.

It ensures only one requestAnimationFrame callback is ever queued at a time. Without it, if ten scroll events fired before the next frame painted, ten redundant rAF callbacks could stack up; the flag collapses them all into a single scheduled update.

Adjust that layer's data-rate attribute. Values near 0 make a layer barely move (appearing far away); values near 1 make it scroll almost with the page (appearing close). The formula (1 - rate) is what converts that rate into an actual pixel offset.