web-dev-qa-db-ja.com

CSS scroll-snap-type with Horizo​​ntal Scrolling

Bootstrap 4、水平スクロール( jquery.mousewheel.js による))とネイティブCSSスナップを使用するWebサイトを作成しました。Chrome 81、古い/サポートされていないブラウザは気にしないでください。

適用する場合scroll-snap-type: x mandatory; CSSに対して、水平スクロールが機能しなくなります(スクロールはまったく発生しません)。 CSSプロパティが削除された場合、スクロールは正常に動作します。ここに私のHTML構造があります:

<div class="portfolio_content container-fluid h-100">
  <div class="row h-100 flex-row flex-nowrap scrollx long_content">
    <div class="col-12 h-100 project d-table" id="project1">
      <div class="project_title d-table-cell align-middle">
        <p>
          Project 1
        </p>
      </div>
    </div>
    <div class="col-12 h-100 project d-table" id="project2">
      <div class="project_title d-table-cell align-middle">
        <p>
          Project 2
        </p>
      </div>
    </div>
    <div class="col-12 h-100 project d-table" id="project3">
      <div class="project_title d-table-cell align-middle">
        <p>
          Project 3
        </p>
      </div>
    </div>
    <div class="col-12 h-100 project d-table" id="project4">
      <div class="project_title d-table-cell align-middle">
        <p>
          Project 4
        </p>
      </div>
    </div>
  </div>
</div>

CSSの場合、主要なエントリは次のとおりです。

html, body {
    height: 100%;
}
.portfolio_content .scrollx {
    overflow-x: scroll;
}

.portfolio_content .long_content {
    scroll-snap-type: x mandatory; /* Comment this to make scrolling works */
}
.portfolio_content .project {
    scroll-snap-align: start;
}
.portfolio_content .project_title {
    display: block;
    margin: auto;
    text-align: center;
}
.portfolio_content .project_title h1 {
    font-size: 96px;
    line-height: 0.8;
}

最後に、これが JSFiddleデモ です。 CSSの9行目にコメントを付けると、デモをスクロールできるようになります。

私の目的は、スクロール時に「プロジェクト」DIVをスナップできるようにすることです。つまり、1つの「プロジェクト」DIVがスクロール後に完全に表示されます。

コードを変更するにはどうすればよいですか?

10
Raptor

短い答え:JavaScriptコードを削除します。

長い答え:_mousewheel.js_は、ホイールイベントをチェックしたり何かを実行したりする場合に役立ちます。この場合、ブラウザをスクロールさせたいだけです。関数でそのイベントを制御し、デフォルトを防止していますが、デフォルトのアクションはまさにあなたが望むものです。

_this.scrollLeft -= delta;_を実行すると、scrollと_end scroll_の2つの処理が実行されます。 _scroll-snap-type_は_end scroll_をリッスンし、要素をスナップします。実際、e.preventDefault();行だけを削除すると、おかしなことが起こります。要素が振動してから変化します。私の理解では、起こっていることは次のとおりです。1)デフォルトのスクロールイベント。これには時間がかかります。一方、2)ホイールイベントは、はるかに短いスクロールイベントをトリガーします。 3)スナップ。 2からのdeltaXは小さいため、開始位置に到達します。 2と3を数回繰り返します。 4)デフォルトのスクロールイベントは、はるかに大きなdeltaXで終了します。 5)スナップ。

要約すると、あなたが望む振る舞いについては、ブラウザにスクロールをさせた方が良いです。他のことをしたい場合は、mousewheelイベントが発生するたびに_end scroll_シグナルを送信しないようにする必要があります。そのためには、マウスホイール関数内の2行のコードを削除して、必要なコードを追加するだけです。

コメントの後に編集:

verticalホイールイベントを水平ホイールイベントに変換したいのですが、前者の答えは、水平ホイールイベントを送信する場合に機能します(タッチパッドを使用して行うことができます)。長い答えはまだ残っているので、問題はどのように問題を回避するかです。私はいくつかの戦略を考えました:

  • イベントをキャンセルして、合成WheelEventを作成します。これまでで最もエレガントなソリューションですが、機能させることができませんでした。イベントが送出されますが、スクロールは発生しません。
_ let lc = document.querySelector('.long_content');
 lc.addEventListener('wheel', function(e) {
   if (e.deltaY !== 0){
     e.preventDefault();
     let evt = new WheelEvent('wheel', {
       deltaX: e.deltaY
     });
     this.dispatchEvent(evt);
   }
   else{
     // The new event gets captured here
   }
  });
_

編集2

これを機能させるには多くの戦略がありますが、それらのすべてに欠点があります。前のスクリプトはスクリプトへの影響は最小限でしたが、ホイールイベントの終了後に変更が始まりました。これと他のパラメータはブラウザに任され、あなたの管理下にはありません。

私はあなたが望むように見える振る舞いを与える別の戦略を備えた第二のフィドルを追加しました( https://jsfiddle.net/vhywmdb5/ )。それがお役に立てば幸いですが、すべてのソリューションを微調整する必要があり、すべてのブラウザーで機能するという保証はありません。残念ながら、現時点では_mousewheel.js_のイベントシミュレーションは壊れています。

0
vqf