简体   繁体   中英

Smooth horizontal wheel only scrolling

It is very annoing to hold shift when wheeling for horizontal scrolling. There are some ways to horizontally scrool with wheel only but they directly copy wheel deltaY into scrollLeft which results in uncomfortable jump-scrolling.

Is there a mobile-friendly way to perform smooth horizontal scrolling on elements using wheel only? By "smooth" I mean something like default browser vertical wheel scroll behaviour.

Smooth scrolling can be achieved by using requestAnimationFrame .

You might want to play with denominator in getScrollStep function to adjust the smoothness of scrolling.

function horizontalWheel(container) {
  /** Max `scrollLeft` value */
  let scrollWidth;

  /** Desired scroll distance per animation frame */
  let getScrollStep = () => scrollWidth / 50 /* ADJUST TO YOUR WISH */ ;

  /** Target value for `scrollLeft` */
  let targetLeft;

  function scrollLeft() {
    let beforeLeft = container.scrollLeft;
    let wantDx = getScrollStep();
    let diff = targetLeft - container.scrollLeft;
    let dX = wantDx >= Math.abs(diff) ? diff : Math.sign(diff) * wantDx;

    // Performing horizontal scroll
    container.scrollBy(dX, 0);

    // Break if smaller `diff` instead of `wantDx` was used
    if (dX === diff)
      return;

    // Break if can't scroll anymore or target reached
    if (beforeLeft === container.scrollLeft || container.scrollLeft === targetLeft)
      return;

    requestAnimationFrame(scrollLeft);
  }

  container.addEventListener('wheel', e => {
    e.preventDefault();

    scrollWidth = container.scrollWidth - container.clientWidth;
    targetLeft = Math.min(scrollWidth, Math.max(0, container.scrollLeft + e.deltaY));

    requestAnimationFrame(scrollLeft);
  });
}

Just pass elements you want to horizontally scroll with wheel in this function:

let list = document.querySelector('.hList');
horizontalWheel(list);

Example:

 function horizontalWheel(container) { /** Max `scrollLeft` value */ let scrollWidth; /** Desired scroll distance per animation frame */ let getScrollStep = () => scrollWidth / 50 /* ADJUST TO YOUR WISH */; /** Target value for `scrollLeft` */ let targetLeft; function scrollLeft() { let beforeLeft = container.scrollLeft; let wantDx = getScrollStep(); let diff = targetLeft - container.scrollLeft; let dX = wantDx >= Math.abs(diff)? diff: Math.sign(diff) * wantDx; // Performing horizontal scroll container.scrollBy(dX, 0); // Break if smaller `diff` instead of `wantDx` was used if (dX === diff) return; // Break if can't scroll anymore or target reached if (beforeLeft === container.scrollLeft || container.scrollLeft === targetLeft) return; requestAnimationFrame(scrollLeft); } container.addEventListener('wheel', e => { e.preventDefault(); scrollWidth = container.scrollWidth - container.clientWidth; targetLeft = Math.min(scrollWidth, Math.max(0, container.scrollLeft + e.deltaY)); requestAnimationFrame(scrollLeft); }); } // // Usage // window.addEventListener('load', () => { let list = document.querySelector('.hList'); horizontalWheel(list); });
 .hList { width: 300px; border: 2px solid red; display: flex; overflow: auto; }.element { display: flex; align-items: center; justify-content: center; color: white; font-family: sans-serif; flex-shrink: 0; width: 150px; height: 75px; background: green; border-right: 2px solid yellow; }.element:last-of-type { border: none; }
 <div class="hList"> <div class="element">Element 1</div> <div class="element">Element 2</div> <div class="element">Element 3</div> <div class="element">Element 4</div> <div class="element">Element 5</div> </div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM