🐢

scroll-snap-typeを使っていてjquery animationが使えない時の対処法

3 min read

概要

  • scroll-snap-typeを使って、フリックできる要素を作ろうとした
  • そしてボタンで任意の位置までスクロールしてくれるようにしようとした
  • そうしたら、jquery の animateでscrollさせてもアニメーションが効かなくなってしまった
  • それの解決した手段を記載する

動かしてみた

コード

index.html
index.html
<body>
    <div id='container' class="container">
      <div class="item bg-red">
        hoge
      </div>
      <div class="item bg-blue">
        fuga
      </div>
      <div class="item bg-yellow">
        piyo
      </div>
      <div class="item bg-green">
        aaa
      </div>
      <div class="item bg-pink">
        bbb
      </div>
      <div class="item bg-black">
        ccc
      </div>
      
    </div>
    
    <div class="buttons">
      <div>
        <button id="pre">前へ</button>
      </div>
      <div>
        <button id="next">次へ</button>
      </div>
    </div>
    
  </body>
main.css
main.css
.container {
  display: flex;
  overflow-x: scroll;
  scroll-snap-type: x mandatory;
  width: 100%;
  height: 200px;
  margin-bottom: 32px;
}

.container::-webkit-scrollbar {
  display: none;
}

.item {
  color: white;
  font-weight: bold;
  font-size: 20px;
  display: flex;
  align-items: center;
  justify-content: center; 
  flex-grow: 0;
  flex-shrink: 0;
  scroll-snap-align: start;
  width: 100%;
  height: 100%;
}

.buttons {
  display: flex;
  justify-content: space-between;
}

.bg-red {
  background-color: red;
}

.bg-blue {
  background-color: blue;
}

.bg-yellow {
  background-color: yellow;
}

.bg-green {
  background-color: green;
}

.bg-pink {
  background-color: pink;
}

.bg-black {
  background-color: black;
}
main.js
main.js
window.onload = function() {
  var $pre = document.getElementById('pre');
  var $next = document.getElementById('next');
  var $container = document.getElementById('container');
  var width = $container.offsetWidth;
  
  // // うまくいかない
  // var onPre = () => {
  //   var left = $container.scrollLeft;
  //   $($container).animate({
  //     scrollLeft: left - width,
  //   }, 256);
  // };
  
  // var onNext = () => {
  //   var left = $container.scrollLeft;
  //   $($container).animate({
  //     scrollLeft: left + width,
  //   }, 256);
  // };
  
  // $pre.addEventListener('click', onPre);
  // $next.addEventListener('click', onNext);
  
  // うまくいく
  var onScroll = (e) => {
    var type = e.currentTarget.id;
    var $children = $container.children;
    var left = $container.scrollLeft;
    var currentIndex = $children.length - Math.floor(($container.scrollWidth - left) / $container.clientWidth);
    var targetIndex = currentIndex + (type ==='next' ? 1 : -1);
    if (targetIndex < 0 || targetIndex >= $children.length) return ;
    $children[targetIndex].scrollIntoView({behavior: "smooth"});
  };

  $pre.addEventListener('click', onScroll);
  $next.addEventListener('click', onScroll);
};

解説

  • jquery animateだとうまく動かないので、scrollIntoViewを使うようにした
  • 今どきの JavaScript と CSS でカルーセルを作ってみたを参考にさせていただきました
  • 最初はscroll-snap-typeとjquery animateで実装しようとしたがアニメーションが動かなかった
  • 次に試したのはアニメーションが始まる前にscroll-snap-typeのCSSを外し、アニメーションが終わったら付け直す、と言うように実装しようとしたが、スマホ側(mobile safari)でうまくいかなかった
  • なので、ターゲットとなる要素を取得し、scrollIntoViewでスクロールさせるようにした
  • 遷移する秒数は指定できないが、要件は満たしていたのでこれで解決

まとめ

  • 実際のコードはindex番号みたいなのをクリックしたらそこまでスクロールしてくれる仕様ではあったが、割愛
  • scrollIntoViewを知っていればjqueryなんて使わずに最初からこれで解決できたと反省
  • 新しいメソッドとかをキャッチアップしていかないとこういうことになるんだなぁと反省しました