SCSSのmixinにしてみました。
DEMO
※ スマートフォンでしか動作しません
HTML
<div data-carousel="0"> <ol class="photos"> <li class="photo"></li> <li class="photo"></li> <li class="photo"></li> <li class="photo"></li> </ol> <ol class="btns"> <li class="btn"></li> <li class="btn"></li> <li class="btn"></li> <li class="btn"></li> </ol> </div>
SCSS
@import "compass/reset"; body { background: #e3e3e3; } @mixin carousel($length) { position: relative; width: 100%; background: #3e3e3e; overflow: hidden; .photos { box-sizing: border-box; position: relative; padding-bottom: 16px; width: $length * 100%; height: 100%; overflow: hidden; transition: left .6s ease-in-out; } .photo { float: left; width: 100 / $length - 0%; height: 100%; background-position: center center; background-size: cover; } .btns { position: absolute; bottom: 0; left: 0; width: 100%; height: 16px; font-size: 10px; text-align: center; } .btn { display: inline-block; border-radius: 50%; // 【TODO】Android 2.X で不安 margin: 0 2px; width: 5px; height: 5px; background: rgba(255, 255, 255, .5); cursor: pointer; } @for $i from 0 through ($length) { &[data-carousel="#{$i}"] { .photos { left: $i * -100%; } .btn:nth-child(#{$i + 1}) { background: rgba(255, 255, 255, 1); } } } } [data-carousel] { @include carousel(4); height: 300px; } .photo { &:nth-child(1) { background: #c3c3c3; } &:nth-child(2) { background: #a3a3a3; } &:nth-child(3) { background: #838383; } &:nth-child(4) { background: #636363; } }
JavaScript
(function buildCarousel(win, doc, $) { "use strict"; function Carousel($elm) { var that = this, diff = 0, x = 0, LIMIT = 100; that.$elm = $elm; that.$photos = $elm.find(".photos"), that.$photo = $elm.find(".photo"), that.$btn = $elm.find(".btn"), that.index = $elm.attr("data-carousel") - 0 || 0; that.length = $elm.find(".photo").length; that.max = that.length - 1; that.timer = null; that.INTERVAL = 5000; $elm.on("touchstart", _start); $elm.on("touchend", _end); that.$photos.width(that.length * 100 + "%"); that.$photo.width(100 / that.length + "%"); that._show(); function _start(evt) { x = evt.originalEvent.touches[0].pageX; } function _end(evt) { diff = x - evt.originalEvent.changedTouches[0].pageX; if (diff > LIMIT) { that.next(); } else if (diff < -LIMIT) { that.prev(); } } } Carousel.prototype._show = function() { var that = this; that.$elm.attr("data-carousel", that.index); that.$photos.css("opacity", 1); // for Android that.$btn.css("opacity", 1); // for Android if (that.length > 1) { clearInterval(that.timer); that.timer = setTimeout(that.next.bind(that), that.INTERVAL); } }; Carousel.prototype.next = function() { var that = this; if (that.length < 2) { return; } that.index = (that.index + 1) % that.length; that._show(); }; Carousel.prototype.prev = function() { var that = this; if (that.length < 2) { return; } if (that.index) { that.index = that.index - 1; } else { that.index = that.max; } that._show(); }; $(function() { var $carousel = $("[data-carousel]"); $carousel.each(function(index) { new Carousel($carousel.eq(index)); }); }); })(this, document, jQuery);