

CSSで無限に横スクロールできるメニューバーをつくりたいです。

自動でスクロールするものではなく、手動で動かすものを作りたいと考えています。

いろいろ調べたのですが、  
このような自動でスクロールされるものではなく、手動の。つまり触らなければ全く動かない横スクロールメニューを構築したいです。  
<https://qiita.com/mk668a/items/e6e73c32b8a8f943c94b>

宜しくお願いいたします


CC BY-SA 4.0
2019-06-04T13:49:28.587
55516
2019-06-05T06:40:18.257
34580
question
javascript html jquery css
CSSで無限に横スクロールできるメニューバーをつくりたい


## 前提

「CSS で作りたい」とのことですが、質問文のリンク先のような動作をする手動のスクロールメニューは、現在使用可能な CSS
の機能のみでは実現出来ません。JavaScript を使用する必要があります。

今回の回答では、 HTML, CSS に、以下のコードを使用します。

[code]

    <div class="infinity-slide">
      <div class="slide">
        <img src="https://cdn.pixabay.com/photo/2018/04/28/22/03/dawn-3358468_1280.jpg" alt>
        <img src="https://cdn.pixabay.com/photo/2018/09/14/22/51/cobblestones-3678292_1280.jpg" alt>
        <img src="https://cdn.pixabay.com/photo/2018/06/29/22/45/wheat-3506758_1280.jpg" alt>
      </div>
    </div>
    
[/code]

[code]

    .slide {
      display: flex;
      width: 50%;
      height: 350px;
      overflow: auto;
    }
    
[/code]

* * *

## 実現方法

質問者さんの実現したいことを行なう方法として、以下の 2 つを考えました。

  * `clone​Node` メソッドを用いて、スクロール位置が右端に達したとき、スライダーのアイテムを複製する。

この方法の良い点は、右端に達したとき、(複製された) 左端の要素が **なめらかに表示** されることです。  
しかし、右端に達するたびに、 **スライダー内の要素数が増えて**
しまいます。右端に追加した要素を消してゆけば要素数は増えませんが、カスタムデータ属性などを使わなければ、要素の順番が乱れてしまいます。

  * `scrollLeft` プロパティを用いて、スクロール位置が右端に達したとき、スクロール位置をスライダーの始端へ戻す。

この方法の良い点は、 `clone​Node` メソッドを使用した方法と違い、 **スライダー内の要素数が増えない**
ことです。もし、スライダー内の要素を追加、削除してはならないのであれば、この方法が簡単だと思います。  
しかし、右端に達するたびに、スクロール位置が左端へ移動するため、 `cloneNode` メソッドを使用した方法のような、
**なめらかな動作になりません** 。

* * *

最終的には、この 2 つの方法を組み合わせ、以下のようなコードになりました。1 度だけ複製を作り、 2 回目以降は `scrollLeft`
プロパティを使っています。このようにすることで、ある程度なめらかな動作になり、要素数も単純に複製していく場合よりも少なくなります。

また、質問文にある Qiita の記事と同じように、最初の複製を行なわず、 HTML に 2 組分スライダー内の要素を記述しておいても良いですが、 2
回同じことを書くのは煩わしいため、このような方法にしました。

[code]

    document.querySelectorAll(".slide").forEach(e => {
      let endOfSliderPosition = null;
    
      e.addEventListener("scroll", function() {
        const slider = this;
    
        if (slider.scrollLeft !== (slider.scrollWidth - slider.clientWidth)) return;
    
        if (endOfSliderPosition === null) {
          endOfSliderPosition = slider.scrollLeft;
          slider.append(...slider.cloneNode(true).childNodes);
        }
        slider.scrollLeft = endOfSliderPosition;
      });
    });
[/code]

[code]

    .slide {
      display: flex;
      width: 50%;
      height: 150px;
      overflow: auto;
    }
    
    .slide>img {
      width: 100%;
      height: auto;
    }
[/code]

[code]

    <div class="infinity-slide">
      <div class="slide">
        <img src="https://cdn.pixabay.com/photo/2018/04/28/22/03/dawn-3358468_1280.jpg" alt>
        <img src="https://cdn.pixabay.com/photo/2018/09/14/22/51/cobblestones-3678292_1280.jpg" alt>
        <img src="https://cdn.pixabay.com/photo/2018/06/29/22/45/wheat-3506758_1280.jpg" alt>
      </div>
    </div>
[/code]


CC BY-SA 4.0
2019-06-04T23:14:39.587
55526
2019-06-05T06:40:18.257
2019-06-05T06:40:18.257
32986
32986
55516
answer