Horizontal Scroll Section
A pinned editorial rail where vertical scroll sweeps through horizontal chapters with measured snap, counter-drift parallax, and a precise progress readout.
About This Effect
A cinematic horizontal scroll section built on ScrollTrigger pinning. The section locks to the viewport while vertical input carries visitors through full-screen editorial chapters, then releases cleanly at the final panel. Panels can use any mix of widths; travel is measured from the track's real scrollWidth, keeping the sequence accurate through resizes, font loads, and content changes. Optional panel-edge snap, per-element parallax, progress bar, and chapter readout are driven by data attributes.
Read the full effect overview
The demo places the rail inside an ordinary vertical page (an opening spread above it and a closing log below) because the turn from vertical to horizontal only reads as a turn if there is vertical scrolling on either side of it.
What's Included
- Pinned horizontal scrolling driven by a single scrubbed x-position tween
- Variable-width panels: distance measured from scrollWidth, not panel counts
- Snap-to-panel edges with measured snap points that survive resizes
- Per-element parallax via containerAnimation ScrollTriggers
- Scroll progress bar plus nearest-panel readout updated without tween churn
- Fully responsive: functional end values plus invalidateOnRefresh
- Configurable scrub smoothing and traverse speed via data attributes
- Accessible: keyboard focus scrolls panels into view, reduced motion stacks panels vertically
Perfect For
- Portfolio and case study galleries with a cinematic sideways flow
- Product feature walkthroughs that step through panels one by one
- Storytelling chapters and timeline sequences on landing pages
- Service or process breakdowns with numbered stages
- Award-style agency sites that need a memorable scroll moment
How It Works
ScrollTrigger pins the section with pin: true and scrubs a single gsap.to tween that translates the track by scrollWidth minus the viewport width. Both the tween's x value and the trigger's end are functions, so combined with invalidateOnRefresh every resize re-measures the layout. Snap points are computed from each panel's offsetLeft on refresh and resolved through gsap.utils.snap. Parallax layers use containerAnimation ScrollTriggers tied to the main tween, and the progress bar is updated in onUpdate through a cached gsap.quickSetter.