Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Don't allow horizontal scroll when scrolling vertically (and vice versa)

Tags:

I have a list, with the overflow-x and overflow-y set to auto. In addition, I've set up momentum scroll, so the touch scrolling works nice in mobile, using webkit-overflow-scrolling: true.

The issue, however, is that I cannot figure out how to disable the horizontal scroll when scrolling vertically. It leads to really bad user experience, as the swiping towards the top left or top right will cause the table to scroll diagonally. When the user is scrolling vertically, I absolutely do NOT want any scrolling horizontally until the user has stopped scrolling vertically.

I've tried the following:

JS:

offsetX: number;
offsetY: number;
isScrollingHorizontally = false;
isScrollingVertically = false;

//Detect the scrolling events
ngOnInit() {
    this.scrollListener = this.renderer.listen(
      this.taskRows.nativeElement,
      'scroll',
      evt => {
        this.didScroll();
      }
    );

    fromEvent(this.taskRows.nativeElement, 'scroll')
      .pipe(
        debounceTime(100),
        takeUntil(this.destroy$)
      )
      .subscribe(() => {
        this.endScroll();
    });
}

didScroll() {
    if ((this.taskRows.nativeElement.scrollLeft != this.offsetX) && (!this.isScrollingHorizontally)){
        console.log("Scrolling horizontally")
        this.isScrollingHorizontally = true;
        this.isScrollingVertically = false;
        this.changeDetectorRef.markForCheck();
    }else if ((this.taskRows.nativeElement.scrollTop != this.offsetY) && (!this.isScrollingVertically)) {
        console.log("Scrolling Vertically")
        this.isScrollingHorizontally = false;
        this.isScrollingVertically = true;
        this.changeDetectorRef.markForCheck();
    }
}

endScroll() {
    console.log("Ended scroll")
    this.isScrollingVertically = false;
    this.isScrollingHorizontally = false;
    this.changeDetectorRef.markForCheck();
}

HTML:

<div
    class="cu-dashboard-table__scroll"
    [class.cu-dashboard-table__scroll_disable-x]="isScrollingVertically"
    [class.cu-dashboard-table__scroll_disable-y]="isScrollingHorizontally"
>

CSS:

&__scroll {
  display: flex;
  width: 100%;
  height: 100%;
  overflow-y: auto;
  overflow-x: auto;
  will-change: transform;
  -webkit-overflow-scrolling: touch;

  &_disable-x {
     overflow-x: hidden;
  }

  &_disable-y {
    overflow-y: hidden;
  }
}

But the everytime I set overflow-x or overflow-y to hidden when its been scrolled, scrolling will glitch and jump back to the top. I've also noticed that webkit-overflow-scrolling: true is the reason why this occurs, when I remove it, the behavior seems to stop, but I absolutely need this for momentum scrolling in mobile devices.

How do I disable horizontal scroll when scrolling vertically?

like image 793
Josh O'Connor Avatar asked Oct 01 '19 18:10

Josh O'Connor


People also ask

How do I not allow horizontal scrolling?

To hide the horizontal scrollbar and prevent horizontal scrolling, use overflow-x: hidden: HTML.

What is causing horizontal scroll?

Web browsers do not take into account the width of the scrollbar on the side of a page when computing width values, so since we have a page that is longer than a single viewport, part of our page is being rendered behind the vertical scroll bar, causing the browser to display a horizontal scroll bar.

How do I enable horizontal scrolling in Visual Studio?

Enables horizontal scrolling by holding down the Shift key and spinning the mouse wheel in Visual Studio 2017, 2019 and 2022. This feature is available in many other programs.

How do you make a fake horizontal scroll in CSS?

To make the fake horizontal scrolling work, we’re going to use a new tween with a scroll trigger. The code that makes this happen is the following: // base vertical scrolling on how wide the container is so it feels more natural. Next, we’ll add some style tags to our Code Module.

Can I scroll horizontally with Divi?

More specifically, we’ve shown you how to scroll horizontally when actually scrolling vertically on your page. This is a custom type of animation that you might have come across at a certain point and wondered how you could do it with DIvi. You were able to download the JSON file for free as well!

How to lock the scroll axis of a Div?

Second idea: in your scroll handler, instead of changing the css classes, set the scroll position of the div directly for the axis you want locked. IE, if you're scrolling horizontally, always set the scrollTop to its starting value. This might also cancel scrolling, not sure.

How do I add a scrollbar to a section in CSS?

Open the section settings and assign a max height in the sizing settings. We’re also setting the vertical overflow to auto. This, in combination with the max height in the previous step, will help us automatically generate a scrollbar on certain screen sizes where the section elements exceed the viewport height.


1 Answers

It's generally a bad practice for your design to need multiaxis scrolling on mobile, unless maybe you're showing big tables of data. That being said, why do you want to prevent it? If a user wants to scroll diagonally, that doesn't seem like the end of the world to me. Some browsers, like Chrome on OSX, already do what you're describing by default.

If you must have single-axis scrolling, a possible solution might be to keep track of the scroll position yourself via touchstart and touchmove events. If you set your drag threshold lower than the browser's, you may be able to do your css stuff before it starts scrolling, avoiding the perceived glitch. Also, even if it does still glitch, you have the touch start and the touch's current location. From these, if you record your div's starting scroll position, you can manually scroll the div to the correct place to counteract it jumping to the top if you have to. A possible algorithm might look like this:

// Touchstart handler
if (scrollState === ScrollState.Default) {
    // Record position and id of touch
    touchStart = touch.location
    touchStartId = touch.id.
    scrollState = ScrollState.Touching

    // If you have to manually scroll the div, first store its starting scroll position:
    containerTop = $('.myContainer').scrollTop();
    containerLeft = $('.myContainer').scrollLeft();
}

// Touchmove handler - If the user has dragged beyond a distance threshold,
// do the css classes swap.
if (touch.id === touchStartId && distance(touchStart, touch.location > threshold) {
    scrollState = ScrollState.Scrolling;
    swapCssClasses();

    // If you have to manually scroll the div to prevent jump:
    $('.myContainer').scrollTop(containerTop + (touch.location.y - touchStart.y));
    // Do the same for horizontal scroll.
}

// Then, listen for debounced scroll events, like you're already doing,
// to reset your state back to default.

Second idea: in your scroll handler, instead of changing the css classes, set the scroll position of the div directly for the axis you want locked. IE, if you're scrolling horizontally, always set the scrollTop to its starting value. This might also cancel scrolling, not sure. You'd have to try it to see if it works.

like image 128
frodo2975 Avatar answered Sep 23 '22 09:09

frodo2975