Hero Parallax Grid — Free HTML CSS JS Scroll Snippet

Hero Parallax Grid · Scroll · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Scroll-to-horizontal
Vertical scroll drives translateX on rows.
Opposite-direction rows
data-dir slides neighbors apart for depth.
Staggered start offsets
Rows begin unaligned for an intentional look.
rAF-throttled scroll
Passive, one transform update per frame.
Overflow-wide rows
max-content rows hold plenty to slide.
Hover lift tiles
Tiles scale up for interactivity.
Themeable tiles
Gradient tiles, swappable for images.
Auto-filled rows
JavaScript generates every tile.

About this UI Snippet

Hero Parallax Grid — Rows Sliding Opposite Ways on Scroll

Screenshot of the Hero Parallax Grid snippet rendered live

The hero parallax grid is the showpiece header where several rows of project tiles slide horizontally as you scroll the page — adjacent rows moving in opposite directions — so the gallery drifts past in a layered parallax. This snippet builds it with plain HTML, CSS, and a lean vanilla JavaScript scroll handler, and it's a favorite opener for studio and portfolio sites.

Scroll drives horizontal movement

Unlike a normal page where scrolling only moves things vertically, here the vertical scroll position is translated into horizontal motion. The update() function reads window.scrollY and, for each row, applies translateX proportional to it: base + scrollY * 0.25 * dir. So as you scroll down, the rows glide sideways. The 0.25 factor controls how fast they slide relative to scroll — smaller is subtler, larger is faster.

Opposite directions per row

Each row carries a data-dir of 1 or -1, and the translate is multiplied by it, so odd rows slide one way and even rows the other. This counter-motion between neighboring rows is the essence of the parallax — your eye reads the opposing layers as depth and energy, whereas rows all sliding the same way would just look like a single moving band. Each row also starts at a different base offset so they aren't aligned at the top edge, which makes the staggering feel intentional.

Efficient scroll handling

The scroll listener is { passive: true } and throttled through requestAnimationFrame with a ticking guard, so the transforms update at most once per frame however fast you scroll. Because the only work per frame is reading scrollY and writing a translateX on three elements, it stays smooth even on long pages. The rows have will-change: transform so the browser promotes them to their own compositor layers.

Overflow-wide rows

Each row is width: max-content and filled with seven tiles in a flex line, so the row is much wider than the viewport and there's plenty of content to slide into view from either side. overflow-x: hidden on the body clips the off-screen tiles so the horizontal motion doesn't create a scrollbar. The tiles themselves lift slightly on hover, so the gallery is interactive as well as animated.

Image-free, themeable tiles

Tiles are gradient rectangles with a label and a bottom scrim, generated in JavaScript from a color palette — so the hero is dependency-free and colorful. Swap each tile's --g background for a real image to turn it into an actual portfolio wall; the parallax logic doesn't care what fills the tiles.

Customizing it

Tune the 0.25 speed factor for more or less drift, add rows (each picks up its direction and a base offset automatically), change the per-row base offsets, adjust tile size, or drop in real images. Combine it with a static headline above, as shown, so the moving grid reads as a backdrop to your title. Pair it with a 3D marquee section or a flip link navigation for a striking studio homepage.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA headline sits above three rows of colorful project tiles.
  2. 2
    Scroll the pageThe rows slide horizontally as you move down.
  3. 3
    Watch the parallaxAdjacent rows drift in opposite directions.
  4. 4
    Hover a tileIt lifts slightly, so the gallery stays interactive.
  5. 5
    Swap in imagesSet each tile's --g to a real project image.
  6. 6
    Tune the speedChange the 0.25 scroll factor for more or less drift.

Real-world uses

Common Use Cases

Studio homepages
Open above a 3D marquee section.
Portfolio heroes
Pair with a flip link navigation.
Agency landing pages
A moving backdrop for an agency hero.
Product showcases
Drift screenshots past a headline.
Photography sites
Slide real shots in parallax rows.
Scroll parallax demos
A reference for scroll-driven horizontal motion.

Got questions?

Frequently Asked Questions

The update function reads window.scrollY and applies translateX to each row as base + scrollY * 0.25 * dir. So scroll position is mapped to horizontal offset rather than vertical, and the rows glide sideways as you scroll the page. The 0.25 factor sets how fast they slide relative to scroll.

Each row has a data-dir of 1 or -1 that multiplies its translate, so adjacent rows slide in opposite directions. The eye reads the opposing layers as depth and motion. Different per-row base offsets also keep the rows from starting aligned, which makes the layering feel deliberate.

No. The rows are width: max-content and wider than the viewport, but overflow-x: hidden on the body clips the off-screen tiles. So tiles slide in and out from the sides without ever adding a horizontal scrollbar to the page.

Yes. The scroll listener is passive and throttled with requestAnimationFrame behind a ticking flag, so it updates at most once per frame. The only per-frame work is reading scrollY and writing a translateX on a few rows, and will-change: transform promotes those rows to their own compositor layers for smooth movement.

Render the rows and tiles from data, then run the scroll handler in a mount effect with cleanup, writing each row's translateX via refs so scrolling doesn't re-render. Keep the ticking flag in a ref. The CSS ports directly. In Tailwind, build the rows with flex and w-max, hide overflow on a wrapper, and apply the computed transforms inline.