nickdekruijk / horizontal-scroller
Add a horizontal scrolling element
Package info
github.com/nickdekruijk/horizontal-scroller
Language:JavaScript
pkg:composer/nickdekruijk/horizontal-scroller
README
Make a natively horizontal-scrolling element better: drag it with the mouse, add prev/next buttons, and (optionally) play nicely with CSS scroll-snap.
Usage
Start with an element that already scrolls horizontally. For the prev/next buttons to position correctly, wrap it in a relatively positioned element:
<div class="relative"> <div class="horizontal-scroller"> <ul class="items"> <li class="item">Item A</li> <li class="item">Item B</li> <li class="item">Item C</li> <!-- … --> </ul> </div> </div>
.relative { position: relative; } .horizontal-scroller { overflow-x: auto; overflow-y: hidden; } .items { list-style: none; padding: 0; display: flex; gap: 40px; } .item { flex: 0 0 200px; padding: 5%; background-color: #ddd; }
Then enhance it:
<script src="horizontal-scroller.js"></script> <script> new HorizontalScroller({ selector: '.horizontal-scroller', }); </script>
Options
All options are optional; the values below are the defaults.
| Option | Default | Description |
|---|---|---|
selector |
".horizontal-scroller" |
Elements to enhance. |
draggable |
true |
Drag the element horizontally with the mouse. While draggable, text selection inside the element is disabled (a drag surface, not prose). |
buttonLeft |
true |
Insert a prev button. |
buttonRight |
true |
Insert a next button. |
buttonClass |
"horizontal-scroller-button" |
Base class for the injected buttons. |
disableSnapOnDrag |
true |
Turn CSS scroll-snap off (inline) while dragging with the mouse and back on for button navigation, so a free drag doesn't snap back mid-drag. No-op if you don't use scroll-snap. Touch swipe and wheel are untouched. |
infinite |
false |
Loop the items by cloning them (disabled automatically when the content isn't wide enough to scroll). |
Buttons
The prev/next buttons are injected as empty elements right after the scroller, so
you style them yourself. They get the base class plus a -left / -right modifier,
and a hide class when the scroller reaches that edge (so you can fade/hide them):
.horizontal-scroller-button { position: absolute; display: block; width: 50px; height: 50px; top: 50%; transform: translateY(-50%); } .horizontal-scroller-button-left { left: 0; } .horizontal-scroller-button-right { right: 0; } .horizontal-scroller-button.hide { display: none; }
Scroll-snap
Snap works out of the box — just declare it in CSS. With disableSnapOnDrag (on by
default) a free mouse drag temporarily turns it off so it doesn't fight the drag,
while the prev/next buttons scroll to an exact item and keep snap on:
.horizontal-scroller { scroll-snap-type: x mandatory; } .item { scroll-snap-align: start; }
Optional: a thin scrollbar
A hairline scrollbar drawn inside a taller, easier-to-grab track, using WebKit's
::-webkit-scrollbar pseudo-elements. The gradients paint a 1px line for the track
and a slightly thicker line for the thumb (swap #1f7a4d for your accent colour):
.horizontal-scroller::-webkit-scrollbar { height: 13px; } .horizontal-scroller::-webkit-scrollbar-track { background: linear-gradient(transparent, transparent 6px, #1f7a4d 6px, #1f7a4d 7px, transparent 7px); } .horizontal-scroller::-webkit-scrollbar-thumb { background: linear-gradient(transparent, transparent 2px, #1f7a4d 2px, #1f7a4d 11px, transparent 11px); } .horizontal-scroller::-webkit-scrollbar-thumb:hover { background: linear-gradient(transparent, transparent 2px, #000 2px, #000 11px, transparent 11px); }
Note: WebKit (Chrome/Safari) only. Do not also set the standard scrollbar-width
or scrollbar-color — Chrome ignores every ::-webkit-scrollbar-* rule the moment
either is present, and you'd lose the hairline. Firefox falls back to its default
scrollbar.
Dragging
While dragging, the element gets a dragging class (e.g. to switch the cursor to
grabbing). See demo.html for a full working demo.