Dual scroll
<cinq-dual-scroll> drives two columns with inverted scroll and spring easing.
Layout, pane content, and zone height stay in your markup and CSS. The
component listens for wheel/touch inside the host and updates column transforms.
Inspired by scroll-you-fools, scoped to a zone instead of hijacking the full page.
Markup
Section titled “Markup”Two columns, identified by data-scroll-column. Stack one pane per “step” inside
each column (same count on both sides works best).
<cinq-dual-scroll spring="0.1" style="height: 70vh; overflow: hidden;"> <div class="dual-scroll__columns"> <div data-scroll-column="left"> <div class="dual-scroll__pane"><!-- pane --></div> <div class="dual-scroll__pane"><!-- pane --></div> </div> <div data-scroll-column="right"> <div class="dual-scroll__pane"><!-- pane --></div> <div class="dual-scroll__pane"><!-- pane --></div> </div> </div></cinq-dual-scroll>Zone height is your responsibility: set an explicit height on
<cinq-dual-scroll> (e.g. 70vh, 100% of a parent, or 100vh for
full-page). The host needs overflow: hidden and touch-action: none so
mobile swipes stay in the zone instead of scrolling the page.
Wheel input is captured when the pointer is over the host (desktop). Touch input starts inside the host (mobile).
Each pane should match the host height. The component sets
--dual-scroll-pane-height on sync so panes can use:
cinq-dual-scroll { overflow: hidden; touch-action: none;}
.dual-scroll__pane { height: var(--dual-scroll-pane-height, 100%);}Column positioning (start off-screen, move on scroll) is also yours. See the demos below.
.dual-scroll-fallback { display: none;}
@media (prefers-reduced-motion: reduce) { cinq-dual-scroll { display: none; }
.dual-scroll-fallback { display: block; }}When prefers-reduced-motion: reduce is set, hide <cinq-dual-scroll> and show
a linear .dual-scroll-fallback in CSS, or set spring="1" yourself if you
keep the effect without inertia. The component does not read that media query.
Scroll or swipe inside the zone. Right column goes down, left goes up.






<cinq-dual-scroll spring="0.1"> <!-- columns + panes --></cinq-dual-scroll>Spring
Section titled “Spring”spring is 0.01-1 (default 0.1). Lower = more inertia, 1 = instant.
spring="0.04": slow, floaty




spring="0.35": snappy




<cinq-dual-scroll spring="0.04">...</cinq-dual-scroll><cinq-dual-scroll spring="0.35">...</cinq-dual-scroll>spring: easing factor (0.01-1, default0.1)- Methods:
init(),destroy(),sync() - CSS variable:
--dual-scroll-pane-height(host height in px, set bysync())
Use init() / destroy() if you need to pause the effect without removing the
element. sync() re-measures after DOM or size changes.
Editorial use
Section titled “Editorial use”This pattern is decorative / editorial. It is not a replacement for normal page scroll or accessible reading flow. Prefer a linear fallback or skip link when the content must be reachable without wheel gestures inside a fixed zone.