Reputation: 4898
I'm implementing a swipe-base navigation, and I'm running into trouble with Chrome.
A newly implemented feature, 'Overscroll history navigation', is triggered when the page is dragged to the right, causing a jump back (to 'history -1'). To prevent this, I'd have to call .preventDefault()
on touchstart
, but this also disables everything from clicking links to scrolling.
How do I prevent browser UI events without interfering with the standard page?
Disabling the feature altogether by setting the appropriate flag in chrome fixes the issue, but isn't practical for a public-facing application. chrome://flags/#overscroll-history-navigation
Upvotes: 3
Views: 6157
Reputation: 1
It's 'touchmove' you will have to stopPropagation() AND preventDefault() inside the callback you can call whatever you need for checking the swipe and your navigation to happen.
Upvotes: 0
Reputation: 4075
I used
html, body {
width: 100%;
height: 100%;
margin: 0;
overscroll-behavior: contain;
}
https://developer.mozilla.org/en-US/docs/Web/CSS/overscroll-behavior
Upvotes: 0
Reputation: 1
onscroll
event on the container and store the 'scrollLeft' value
this.offsetX = event.currentTarget.scrollLeft;
onwheel
event on the same container and use this handlervar offset = 0;
document.getElementById("1")
.addEventListener("scroll", function(event) {
offset = event.currentTarget.scrollLeft;
});
document.getElementById("1")
.addEventListener("wheel", function(event) {
// if we reach the left side of the scrollable content, and we scroll further -> block the event
if (offset === 0 && event.deltaX <= 0) {
event.preventDefault();
}
});
.container {
width: 100%;
background-color: blue;
overflow: auto;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
}
.element {
display: inline-block;
min-width: 100px;
height: 50px;
margin: 10px;
background-color: red;
}
<div id="1" class="container">
<div class="element">
1
</div>
<div class="element">
2
</div>
<div class="element">
3
</div>
<div class="element">
4
</div>
<div class="element">
5
</div>
<div class="element">
6
</div>
<div class="element">
7
</div>
<div class="element">
8
</div>
</div>
Upvotes: 0
Reputation: 464
To leave scrolling vertical working and moving elemets horizontally you need to check if moving is more along x then y axis by comparing coordinates differences using Math.abs(), then decide to call .preventDefault() in touchmove event or not.
Sounds little strange but i think it is the only way to control this behemoth feature "Overscroll history navigation". ble.
$(function () {
function extract(e) {
if (e.changedTouches) {
e = e.changedTouches;
if (e['0'])
e = e['0'];
}
return e;
}
var div = $('div').html('Drag me left and right and see that Overscroll is disabled & drag me up and down to see that scroll still works<br /><br /><br />'.repeat(300));
var di = div.get(0); // get native dom element
var startx, lastx, lasty, l = false, active = false;
di.addEventListener("touchstart", function (e) {
active = true;
e = extract(e);
// init
lastx = e.pageX;
lasty = e.pageY;
l = parseInt(div.css('left'), 10);
startx = e.pageX;
}, false);
di.addEventListener("touchmove", function (ee) {
if (active) {
var e = extract(ee);
// check if preventDefault to cancel Overscroll history navigation only if it's needed
if (Math.abs(lastx - e.pageX) > Math.abs(lasty - e.pageY)) {
ee.preventDefault();
}
// update x y to next above calculation
lastx = e.pageX;
lasty = e.pageY;
// repositioning
div.css({left: (l + (e.pageX - startx))+'px'})
}
}, false);
di.addEventListener("touchend", function (e) {
active = false;
}, false);
});
Complete example to test on touch devices: DEMO
Upvotes: 0
Reputation: 4898
I eventually figured out a solution:
Chrome fires at least touchstart
and touchmove
before overscrolling. By tracking the direction of those events, an overscroll can be filtered from regular scrolling.
I've written up the code for this Hammer.js issue.
Upvotes: 2