スライダ実装におけるCSSとJSの棲み分け

by Sho KUWABARA

HTML

<aside id="slider">
    <div class="banners">
        <ul>
            <li><a href="#">1</a></li>
            <li><a href="#">2</a></li>
            <li><a href="#">3</a></li>
            <li><a href="#">4</a></li>
            <li><a href="#">5</a></li>
            <li><a href="#">6</a></li>
            <li><a href="#">7</a></li>
            <li><a href="#">8</a></li>
            <li><a href="#">9</a></li>
            <li><a href="#">10</a></li>
        </ul>
    </div>
    <div class="pager">
        <a class="prev" href="#">&lt;</a>
        <a class="next" href="#">&gt;</a>
    </div>
</aside>

SCSS

/** module */
#slider {
    position: relative;
    width: 512px;
    height: 85px;
    margin: 30px auto;
    
    .banners {
        position: absolute;
        width: 512px;
        height: 85px;
        overflow: hidden;
        
        ul {
            position: absolute;
            width: auto;
            height: 100%;
            left: 0;
            top: 0;
            transition: left .4s ease-in-out; /*アニメーションはCSSで*/
        }
        
        li {
            float: left;
            margin: 0 4px;
            
            a {
                background: #f0f0f0;
                display: block;
                width: 120px;
                height: 80px;
                box-shadow: 0 2px 3px 0 rgba(0,0,0,0.7);
                text-align: center;
                line-height: 80px;
                text-decoration: none;
                color: #ccc;
                font-size: 20px;
            }
        }
    }
    
    .pager {
        a {
            position: absolute;
            display: block;
            top: 20px;
            text-align: center;
            text-decoration: none;
            color: #fff;
            font-size: 20px;
            line-height: 2em;
            width:2em;
            height: 2em;
            border-radius: 1em;
            background-color: #333;
            
            &.prev { left : -50px; }
            &.next { right: -50px; }
            
            &:hover  { background-color: #666; }
            &:active { background-color: #999; }
            &.disable {
                cursor: default;
                opacity: 0.2;
                pointer-events: none;
            }
        }
    }

}

JavaScript

(function($){
  'use strict';

  var slider, nav, container, banner, btnPrev, btnNext, max, count, pitch;

  function sliderInit() {
       slider = $('#slider');
    container = slider.find('.banners > ul');
          nav = slider.find('.pager');
      btnPrev = nav.find('.prev');
      btnNext = nav.find('.next');
          max = container.find('li').length;   //バナーの数
        count = 1;                             //その時一番左に表示されているバナーが何番目か
        pitch = 128;                           //バナー同士の距離px

    if(max <= 4){
      btnNext.hide();
      btnPrev.hide();
    }
    else {
      container.width((max)*pitch); //バナーの個数分親の横幅を伸ばす
      sliderUpdate();
      
      btnPrev.on('click', function(){
        count -= 1;
        sliderUpdate();
        return false;
      });
      btnNext.on('click', function(){
        count += 1;
        sliderUpdate();
        return false;
      });
    }
  }

  function sliderUpdate() {

    //ulのleftを更新(モーションはCSS側で勝手に動く,なので連打対応とか不要!)
    container.css('left', -1*(count-1)*pitch);

    //条件に応じて< >ボタンの表示/非表示の更新
    if(count <= 1) {
      btnPrev.addClass('disable');
      btnNext.removeClass('disable');
    }
    else if(count > 1 && count < (max-3)){
      btnPrev.removeClass('disable');
      btnNext.removeClass('disable');
    }
    else if(count >= (max-3)){
      btnPrev.removeClass('disable');
      btnNext.addClass('disable');
    }

  }

  $(function(){
    sliderInit();
  });

})(jQuery);