ChatGPT解决这个技术问题 Extra ChatGPT

Any way to prevent horizontal scrolling triggering swipe back gesture on OS X Lion Safari?

I am working on a UI that uses horizontal scrolling in a div element (using overflow: scroll). I cannot scroll to the left, because it would start the animation for going back in history. Likewise, I cannot scroll to the right when there is a website to go forward to.

It works well on other browsers including Chrome on OS X Lion, which also supports swiping to go back in history. (At one point while I was developing, scrolling in a div worked on Safari, too. I've added event handlers and html which probably broke scrolling, but I have no clue what made it change.)

Ideally, I would like to prevent going back or forward in history when scrolling on a specific div (even when it has reached an end.)

Update: I tried adding jQuery.mousewheel and it somehow fixed the problem. (I just attached a empty event handler on .mousewheel().) I am still looking for a definitive answer.

As a Lion user - please don't do this - when your little site overrides my OS settings, it's annoying!
@RichBradshaw As a lion user, when our OS fundamentally changes the event model for the internet, deal with other people not wanting to have to consider "well how does this niche computer operating system fundamentally change the event model".\
To be honest, I was really playing devils advocate - but it's worth considering. I'm not sure most people even know you can scroll sideways - on most peoples computers they still have a mouse with a scrollwheel. It's worth considering carefully whether the site design is worth pursuing.
@RichBradshaw Thank you for your thoughtful comments. Horizontal scrolling is only one aspect of the UI that I am working on. As a Lion user I have been annoyed by sites that use horizontal scrolling, because I would accidentally go back in history. I think it would be a good compromise to disable it in a small section where scrolling is expected to work in another way.
Anyone know how to turn off the swipe left to trigger back at the browser level? I've loved using the two finger swipe for horizontal scrolling for a long time, but now it's annoying when it also triggers back/forward events. Don't see it anywhere in Safari Preferences.

L
Luc

In order to allow an element (e.g. a <div>) to scroll with a trackpad but prevent the browser from going back to the previous page, you need to prevent the browser's default action.

You can do this by listening to the mousewheel event on the element. Using the scroll properties of the element and the deltaX/Y properties on the event, you can prevent and stop the default action when it goes below zero or above the width/height.

You can also use the delta information to manually scroll when you are preventing the whole scroll operation. This allows you to actually get to zero rather than stopping at 10 pixels or something.

// Add the event listener which gets triggered when using the trackpad 
element.addEventListener('mousewheel', function(event) {
  // We don't want to scroll below zero or above the width and height 
  var maxX = this.scrollWidth - this.offsetWidth;
  var maxY = this.scrollHeight - this.offsetHeight;

  // If this event looks like it will scroll beyond the bounds of the element, prevent it and set the scroll to the boundary manually 
  if (this.scrollLeft + event.deltaX < 0 || 
     this.scrollLeft + event.deltaX > maxX || 
     this.scrollTop + event.deltaY < 0 || 
     this.scrollTop + event.deltaY > maxY) {

    event.preventDefault();

    // Manually set the scroll to the boundary
    this.scrollLeft = Math.max(0, Math.min(maxX, this.scrollLeft + event.deltaX));
    this.scrollTop = Math.max(0, Math.min(maxY, this.scrollTop + event.deltaY));
  }
}, false);

This works on Chrome, Safari, and Firefox on Mac. I haven't tested on IE.

This solution will only affect the element in question and will let the rest of the page behave as normal. So you can use your browser as expected and go back a page, but while inside the element you won't accidentally go back when you didn't mean to.


After fixing the two errors in this code I tested it, and it does not work. Chrome 54, macOS 10.12.1
m
micho

I've been looking for a solution for days. What I have so far is in this plugin:

https://github.com/micho/jQuery.preventMacBackScroll

It disabled scrolling for OSX Chrome (I couldn't find a way to disable it for OSX Safari) when you scroll left and up.

I hope that helps, please contribute to the project with any bugs you find, or if you find a way to disable this annoying behavior for Safari


For anyone looking for a POJS solution, this plugin just does what's outlined in other answers below: it checks to see if the scroll delta is below 0 and if so calls the event's preventDefault method.
I downvote for using jQuery where is no need for jQuery.
^ Like the teacher who gives you bad marks because you did not use his method of solving the problem.
I upvoted expressly to overwrite @DiligentKeyPresser's downvote. The poster didn't ask for a vanilla js solution. I appreciate micho's effort to develop a solution and post it here for everyone's benefit.
L
Les Nie

Yes, in order to disable default behavior (swipe, pinch etc.) all you have to do is to add:

event.preventDefault();

In you case simply register touchMove listener and use preventDefault() there (in function "touchmove").

element.addEventListener("touchmove", touchMove, false);

Sorry, but I can't accept this as an answer because it is misleading. The question is about mousewheel event. Also event.preventDefault() is a jQuery method.
No problem :) Maybe someone else would benefit from this answer. And this isnt jQuery only method <developer.mozilla.org/en/DOM/event.preventDefault>. using it you can disable default behavior for any event, not only for touchmove from my example. Did you tried it?
Oops, you are right. A quick inspection of event object didn't show preventDefault as a property, so I dismissed it. I am not sure about this either, but isn't touchmove specific to touch screen devices?
Also, at this point, I am pretty sure this is just a bug in Safari, because I cannot reliably reproduce the situation in my original question.
T
Tad Lispy

In modern browsers this should do the trick:

element.addEventListener("wheel", function(event) {
  if (Math.abs(event.deltaX) < Math.abs(event.deltaY)) {
    // Scrolling more vertically than horizontally. Let it be!
    return
  }
  const scrollLeftMax = this.scrollWidth - this.offsetWidth
  if (
    this.scrollLeft + event.deltaX < 0 ||
    this.scrollLeft + event.deltaX > scrollLeftMax
  ) { 
    event.preventDefault()
  }
}, false)

Side note: Firefox has a handy scrollLeftMax property, but it's not standard, so it's better to calculate it ourselves.


Tad, thank you. This saved me a lot of time.
N
NinjaKC

Look into the CSS3 style

-ms-touch-action: none;
touch-action: none;

This works perfectly for me when the used app is only expected on HTML5 / CSS3 capable browsers.


@Ciprian - Odd, works for me on an older iPhone 3GS with safari, and android's version of safari running on a Moto X. What version of safari browser did you test on? And device? All I can think is apple did an update, and I don't have anything newer than the 3GS to test on, so, there is that ;)
m
mzpn

I also used jQuery mousewheel, attaching this callback:

onMousewheel: function(e, delta, deltaX, deltaY){
  e.preventDefault();
  $('leftElement').scrollLeft($('leftElement').scrollLeft() + deltaX); // leftElement =     container element I want to scroll left without going back/forward
  $('downElement').scrollTop($('downElement').scrollTop() - deltaY); // this was another element within the container element
}

For future readers, mousewheel is deprecated and wheel is recommend instead. element.addEventListener('wheel', e => e.preventDefault())
A
Adler Faulkner

Piggy backing off of https://github.com/micho/jQuery.preventMacBackScroll posted by micho I have made this possible in both safari and chrome. Also, I made it work for both left scrolling and right scrolling.

(Sorry that this is in coffeescript. It wouldn't be hard to translate back into javascript)

$(document).on 'ready', ->

# This code is only valid for Mac
if !navigator.userAgent.match(/Macintosh/)
    return

# Detect browsers
# http://stackoverflow.com/questions/5899783/detect-safari-using-jquery
is_chrome = navigator.userAgent.indexOf('Chrome') > -1
is_safari = navigator.userAgent.indexOf("Safari") > -1
is_firefox = navigator.userAgent.indexOf('Firefox') > -1

# Handle scroll events in Chrome, Safari, and Firefox
if is_chrome || is_safari || is_firefox

    $(window).on 'mousewheel', (event) ->
        dX = event.deltaX || event.originalEvent.deltaX
        dY = event.deltaY || event.originalEvent.deltaY

        # If none of the parents can be scrolled right when we try to scroll right
        prevent_right = dX > 0 && $(event.target)
            .parents().addBack()
                .filter ->
                    return this.scrollWidth - this.clientWidth != 0 &&
                     $(this).scrollLeft() < this.scrollWidth - this.clientWidth &&
                     ($(this).css('overflow-y') == 'scroll' || $(this).css('overflow-y') == 'auto')
                .length == 0

        # If none of the parents can be scrolled left when we try to scroll left
        prevent_left = dX < 0 && $(event.target)
            .parents().addBack()
                .filter ->
                    return $(this).scrollLeft() > 0
                .length == 0

        # If none of the parents can be scrolled up when we try to scroll up
        prevent_up = dY > 0 && !$(event.target)
            .parents().addBack()
                .filter ->
                    return $(this).scrollTop() > 0
                .length == 0

        # Prevent minute left and right scroll from messing up vertical scroll
        if (prevent_right || prevent_left) && Math.abs(dY) > 5 && !prevent_up
            return
        # Prevent futile scroll, which would trigger the Back/Next page event
        if prevent_left || prevent_up || prevent_right
            event.preventDefault()

H
Hoang Tran

I came here while searching for the same thing but from user's point of view. So here's the FF setting that affect this:

browser.gesture.swipe.left
browser.gesture.swipe.right

set them to an empty string (delete what is there)

Source: https://forums.macrumors.com/threads/disabling-firefox-back-forward-from-horizontal-scrolling.111589/