JSFiddle - React, Tailwind, and code Playground
by timwhitlock
HTML
<div class="wrap" id="testwrap">
<div class="grid">
<a href="#" class="item">1</a>
<a href="#" class="item">2</a>
<a href="#" class="item">3</a>
<a href="#" class="item">4</a>
<a href="#" class="item">5</a>
<a href="#" class="item">6</a>
<a href="#" class="item">7</a>
<a href="#" class="item">8</a>
<a href="#" class="item">9</a>
<a href="#" class="item">10</a>
<a href="#" class="item">11</a>
<a href="#" class="item">12</a>
<a href="#" class="item">13</a>
<a href="#" class="item">14</a>
<a href="#" class="item">15</a>
<a href="#" class="item">16</a>
<a href="#" class="item">17</a>
<a href="#" class="item">18</a>
<a href="#" class="item">19</a>
<a href="#" class="item">20</a>
</div>
</div>
CSS
body {
margin: 0;
font: 11px Arial;
}
.wrap{
width: 100%;
max-width: 738px;
height: 110px;
overflow-x: scroll;
white-space: nowrap;
background: #f5f5f5;
}
.grid {
width: 3740px; /* 20 x 187 */
}
.grid a {
background: #ccc;
text-decoration: none;
color: #333;
font-size: 20px;
display: block;
float: left;
text-align: center;
vertical-align: middle;
width: 137px;
height: 50px;
padding: 20px;
margin: 0 10px 0 0;
}
.grid a:nth-child(2n+2) {
background-color: #ddd;
}
.grid a:first-child,
.grid a:last-child {
background-color: #666;
color: #fff;
}
.grid a.clicked {
color: #fff;
background-color: #cc0000;
}
/**
* Progressive enhancement for IE10 touch properties
*/
.wrap {
-ms-scroll-snap-points-x: snapInterval( 0px, 187px );
-ms-scroll-snap-type: mandatory;
-ms-scroll-chaining: none;
}
JavaScript
/**
* Add swipe/scroll effect for touch enabled browsers except IE10 which will use CSS only
*/
/**
* Scroll animator using setInterval
*/
function initScroller( el, onEnd ){
var t, // <- timeout id
ppf, // <- pixels per frame
maxFunc, // <- Math.max, or Math.min depending on direction of scroll
scrollNow, // <- current element scrollLeft
scrollTarget, // <- target scrollLeft
interval = 16; // <- 60fps
function onInterval(){
scrollNow = Math.max( 0, maxFunc( scrollTarget, scrollNow + ppf ) );
el.scrollLeft = scrollNow;
if( scrollTarget === scrollNow ){
stop();
onEnd && onEnd();
}
}
function start(){
stop();
t = setInterval( onInterval, interval );
}
function stop(){
t && clearInterval(t);
t = null;
}
// expose public functions, stop and scroll
return {
stop: stop,
scroll: function ( scrollLeft, speed ){
scrollTarget = scrollLeft;
scrollNow = el.scrollLeft;
var direction = scrollTarget > scrollNow ? 1 : -1;
maxFunc = Math[ direction === 1 ? 'min' : 'max' ];
ppf = Math.round( speed * interval * direction );
start();
}
};
}
/**
* Enhance with touchstart and touchend for swipe inertia
*/
function initSwiper( el, onStart, onEnd ){
var xstart = 0, // <- initial scroll position on first touch
tstarts = [], // <- time each touch started
xoffset = [], // <- initial x position of each touch
yoffset = []; // <- initial y position of each touch
/**
* Utility for getting current time in milliseconds
*/
var now = Date.now || function(){
return new Date().getTime();
};
/**
* Initialize swipe on touchstart
*/
function onTouchStart( event ){
var t = now();
...