特にタッチ操作ができるデバイスではJSでスクロール機能を提供するより、ブラウザそのもののスクロール機能を利用したほうがよいと思う。
思ったのでjQueryでささっと書いてみた。
##サンプル
http://codepen.io/blurblue/pen/avmzGj
スマホで「1x」で見るとちょうどいいかと。
タッチデバイスでは overflow: auto; にして、それ以外では overflow: hidden; にしてスクロール機能を提供してもよいかもしれない(PCで見るとスクロールバーがかっちょわるい)。
なんにしろ、touchstartからtouchmoveやら何やらを拾ってスクロール機能を提供するのはすごく無駄だと思った次第。
iOS、Androidだときれいにスクロールバーが消えてくれるので全然見やすいし、このほうが断然実装が楽で軽い。
以下必要部分だけのコード。
細かいところはcodepenに。
##HTMLコード
<div class="slider_wrapper">
<p class="slider_btn prev js-slider-prev">prev</p><!--
--><div class="slider js-slider">
<ul class="slider_body js-slider-body">
<li class="slider_item">item1</li><li class="slider_item">item2</li><li class="slider_item">item3</li><li class="slider_item">item4</li><li class="slider_item">item5</li>
</ul>
</div><!--
--><p class="slider_btn next js-slider-next">next</p>
</div>
##CSSコード
.slider_wrapper {
width: 320px;
.slider {
display: inline-block;
border: 1px solid #aaa;
width: 180px;
padding: 1em 0;
vertical-align: middle;
overflow-x: auto;
}
.slider_body {
width: 10000px; /* sample */
box-sizing: border-box;
}
.slider_item {
display: inline-block;
width: 160px;
margin-left: 10px;
padding: 1em 0;
background-color: #ccc;
vertical-align: middle;
text-align: center;
&:first-child {
margin-left: 0;
}
}
.slider_btn {
position: relative;
display: inline-block;
width: auto;
margin: 0 0.4em;
border: 1px solid #aaa;
background-color: #eee;
padding: 0.5em;
color: #444;
vertical-align: middle;
cursor: pointer;
&:hover {
background-color: #fafafa;
}
&.prev {
padding-left: 1.5em;
&:before {
content: "<";
display: block;
position: absolute;
left: 0.5em;
}
}
&.next {
padding-right: 1.5em;
&:before {
content: ">";
display: block;
position: absolute;
right: 0.5em;
}
}
&.disabled {
color: #fff;
background-color: #aaa;
cursor: default;
}
}
}
##jQueryコード
var Slider = {};
Slider.sliderBody = $('.js-slider');
Slider.items = Slider.sliderBody.find('li');
Slider.itemWidth = Slider.items.eq(0).width();
Slider.itemMargin = parseInt(Slider.items.eq(1).css('margin-left'), 10);
Slider.btnNext = $('.js-slider-next');
Slider.btnPrev = $('.js-slider-prev');
Slider.moveVal = function(which){
var defaultVal = Slider.itemWidth + Slider.itemMargin,
left = Slider.sliderBody.scrollLeft();
var val = 0;
if(left%defaultVal == 0){
if(which == 'next'){
val = left + defaultVal;
} else {
val = left - defaultVal;
}
} else {
if(which == 'next'){
val = (Math.floor(left/defaultVal) + 1) * defaultVal;
} else {
val = (Math.floor(left/defaultVal)) * defaultVal;
}
}
return val;
};
Slider.btnControll = function(){
var left = Slider.sliderBody.scrollLeft(),
next = Slider.sliderBody.width() + left < Slider.scWidth,
prev = left > 0;
if(next){
Slider.btnNext.removeClass('disabled');
} else {
Slider.btnNext.addClass('disabled');
}
if(prev){
Slider.btnPrev.removeClass('disabled');
} else {
Slider.btnPrev.addClass('disabled');
}
};
/* next */
Slider.onNext = function(){
var moveTo = Slider.moveVal('next');
Slider.sliderBody.scrollLeft(moveTo);
Slider.btnControll();
}
/* prev */
Slider.onPrev = function(){
var moveTo = Slider.moveVal('prev');
Slider.sliderBody.scrollLeft(moveTo);
Slider.btnControll();
}
/* init */
Slider.init = function(){
Slider.scWidth = Slider.items.length * (Slider.itemWidth + Slider.itemMargin) - Slider.itemMargin;
Slider.sliderBody.find('.js-slider-body').width(Slider.scWidth + 'px');
$('body').on('load', Slider.btnControll());
Slider.sliderBody.scroll(function(){
Slider.btnControll();
});
$('.js-slider-prev').on(_EVENT_TOUCH.START, function(){
if(!$(this).hasClass('disabled')){
Slider.onPrev();
}
});
$('.js-slider-next').on(_EVENT_TOUCH.END, function(){
if(!$(this).hasClass('disabled')){
Slider.onNext();
}
});
};
Slider.init();
前・次ボタンのアクションとかは簡素化してアニメーションとかは省きました。