How do I programmatically handle swipe-to-scroll behavior?

4 weeks ago 36
ARTICLE AD BOX

I noticed that the template I am currently working on has a vertical scrolling issue when tested on tablet and/or mobile devices.

Here is the current behavior:

GIF demo with issues

Remarks: There are issues with the scrolling behavior. Mouse wheel scrolling works properly, but swipe-to-scroll is not functioning as expected.

Here is the reference that I am unable to replicate in my template:

GIF demo with issues

Remarks: This has almost the same code structure as the template with the issue.


Here's the relevant code snippets:

<div class="zld-scrollbar-custom"> <ul class="the-list-tasks"> <li><a class="active" href="#tip-answer-1-11">Consejo # 1/11</a></li> <li><a href="#tip-answer-2-11">Consejo # 2/11</a></li> <li><a href="#tip-answer-3-11">Consejo # 3/11</a></li> <li><a href="#tip-answer-4-11">Consejo # 4/11</a></li> <li><a href="#tip-answer-5-11">Consejo # 5/11</a></li> <li><a href="#tip-answer-6-11">Consejo # 6/11</a></li> <li><a href="#tip-answer-7-11">Consejo # 7/11</a></li> <li><a href="#tip-answer-8-11">Consejo # 8/11</a></li> <li><a href="#tip-answer-9-11">Consejo # 9/11</a></li> <li><a href="#tip-answer-10-11">Consejo # 10/11</a></li> <li><a href="#tip-answer-11-11">Consejo # 11/11</a></li> </ul> </div>
/** * Place the box inside the container with the class .zld-scrollbar-custom. * The child box should have an auto height, but .zld-scrollbar-custom should have a defined height. */ function ZLDCustomScrollbarsInit() { $(".zld-scrollbar-custom").each(function (index_scrollbar) { const scroll_thumb_id = `scroll-thumb-${index_scrollbar}`; const inner_box = $(this).find(">*").first(); // Both container and inner_box refer to the same element: the first box inside .zld-scrollbar-custom that will scroll. const container = inner_box; const zldScrollPanel = $(this); if (zldScrollPanel.attr("data-initilized") !== "Y") { // Add the classes of the child box to its parent. zldScrollPanel.attr("class", `${zldScrollPanel.attr("class")} ${inner_box.attr("class")}`); inner_box.addClass("scrollable-content"); zldScrollPanel.attr("data-initilized", "Y"); zldScrollPanel.append(` <div class="scroll-y"> <div class="scroll-thumb" id="${scroll_thumb_id}"></div> </div> `); window[`point-${scroll_thumb_id}`] = { x: 0, y: 0 }; /** * Using the plugin for dragging (https://interactjs.io/) */ interact(`#${scroll_thumb_id}`).draggable({ listeners: { start(event) { $("body").addClass("noselect"); $(event.target).addClass("dragged"); }, end(event) { $("body").removeClass("noselect"); $(event.target).removeClass("dragged"); }, move(event) { move(event.target, event.dx, event.dy); }, }, }); /** * Container is the content box that should have scrollbars. */ container.on("mousewheel DOMMouseScroll", function (e) { // If the parent of the container has the class .not-scrollable, enable standard scrolling. if (container.parent().is(".not-scrollable")) { return true; } const deltaMovingY = getMaxScrollY() > 200 ? 10 : 100; const delta = e.originalEvent.detail !== undefined && e.originalEvent.detail !== 0 ? e.originalEvent.detail * -1 // Firefox : e.originalEvent.wheelDelta; // Chrome if (delta / 120 > 0) { move($(`#${scroll_thumb_id}`)[0], 0, 0 - deltaMovingY); } else { move($(`#${scroll_thumb_id}`)[0], 0, deltaMovingY); } // Prevent window scrolling when hovering over this element. return false; }); // Touch event handling let touchStartY = 0; container.on("touchstart", function (e) { touchStartY = e.originalEvent.touches[0].clientY; }); container.on("touchmove", function (e) { if (container.parent().is(".not-scrollable")) { return true; } const touchEndY = e.originalEvent.touches[0].clientY; const deltaMovingY = getMaxScrollY() > 200 ? 10 : 100; const deltaY = touchStartY - touchEndY; // Determine swipe direction if (deltaY > 0) { move($(`#${scroll_thumb_id}`)[0], 0, deltaMovingY); // Scroll down } else { move($(`#${scroll_thumb_id}`)[0], 0, -deltaMovingY); // Scroll up } touchStartY = touchEndY; // Update for smooth scrolling e.preventDefault(); // Prevent default scrolling }); } const move = function (element, dx, dy) { const thumb = $(element); const parentThumb = thumb.parent(); const zldScrollBarPanel = parentThumb.closest(".zld-scrollbar-custom"); const position = window[`point-${scroll_thumb_id}`]; position.y += dy; if (position.y < 0) { position.y = 0; } else if (position.y + thumb.height() > parentThumb.height()) { position.y = parentThumb.height() - thumb.height(); } element.style.transform = `translate(${position.x}px, ${position.y}px)`; const totalFreeSpace = parentThumb.height() - thumb.height(); // When the thumb is larger than the parent, scrolling is not needed. if (totalFreeSpace <= 0) return; const percentMove = position.y / totalFreeSpace; container.scrollTop(getMaxScrollY() * percentMove); }; const getMaxScrollY = function () { const thumb = $(`#${scroll_thumb_id}`); const parentThumb = thumb.parent(); const zldScrollBarPanel = parentThumb.closest(".zld-scrollbar-custom"); const scrollMaxY = container[0].scrollMaxY || container[0].scrollHeight - container[0].clientHeight; return scrollMaxY; }; const thumb = document.getElementById(scroll_thumb_id); if (thumb) { const position = window[`point-${scroll_thumb_id}`]; requestAnimationFrame(() => { const parentThumb = $(thumb).parent(); const totalFreeSpace = parentThumb.height() - $(thumb).height(); const maxScroll = container[0].scrollHeight - container[0].clientHeight; if (totalFreeSpace > 0 && maxScroll > 0) { const percentScrolled = container.scrollTop() / maxScroll; position.y = totalFreeSpace * percentScrolled; } thumb.style.transform = `translate(${position.x}px, ${position.y}px)`; }); } const setScrollbasSize = function () { // Reset the scrollbar sizes (you can complete this if necessary). }; // Resetting the scrollbar size. setScrollbasSize(); // When initializing for the first time or resizing the browser, reset the positions. if (1) { move($(`#${scroll_thumb_id}`)[0], 0, 0); } // Check if the container contains enough content to enable scrolling. if (container[0].scrollHeight > container[0].clientHeight) { container.closest(".zld-scrollbar-custom").removeClass("not-scrollable"); } else { container.closest(".zld-scrollbar-custom").addClass("not-scrollable"); } }); } $(window).on("resize", function () { ZLDCustomScrollbarsInit(); }); $(window).on("orientationchange", function () { ZLDCustomScrollbarsInit(); }); $(window).on("load", function () { ZLDCustomScrollbarsInit(); }); $(document).ready(() => { // Handle scrollbar initialization for elements that are hidden initially. window.addEventListener(ON_TRANSITION_TO_SHOW_ENDED, () => { ZLDCustomScrollbarsInit(); }); });

I also tried applying scroll-behavior: smooth, but the issue persists.


What I’m looking for is not just a code fix, but guidance on how to handle this behavior generally. I’m trying to ensure the vertical scroll works correctly on mobile and tablet, but I can't figure out what is causing the swipe-to-scroll to misbehave.

Read Entire Article