Quick disclaimer–I know there are similar questions but they don't provide the answer I'm looking for.
I'm trying to disable scrolling entirely when the page loads but still be able to listen to when user attempts to scroll. The goal is to trigger an animation function when user attempts to scroll and once the animation completes, the scroll would be re-enabled back to it's normal state.
I've tried to disable scroll and play my animation after user tries to scroll like this:
function blogHeaderMagic() {
//disable scroll function
disableScroll()
//my animation and on a callback you'll see I call allowScroll function to allow scroll normally once animation completes
TweenMax.to("#post-hero-media-wrapper", 1, {height:54, onComplete: allowScroll });
scrolled = true
}
document.onscroll = function() {
if( scrolled == false){
blogHeaderMagic();
}
}
And while this works great, in Chrome or Safari, it isn't such a smooth effect because when user first attempts to scroll, scroll is enabled so they can scroll like 100px from the top and only then scroll locks. This is why I would first like to disable the scroll and when user attempts to scroll (although they won't be able to) I would like to detect their attempt to scroll and trigger my animation function on that detection. Is this possible?
Answer
You could set the body tag to overflow:hidden; which won't allow the user to scroll and use these event handler, then put back the overflow property to whatever it was (probably auto if you didn't changed it in the first place).
// IE9, Chrome, Safari, Opera
document.body.addEventListener("mousewheel", MouseWheelHandler, false);
// Firefox
document.body.addEventListener("DOMMouseScroll", MouseWheelHandler, false);
function MouseWheelHandler() {
alert('scrolling with the mouse');
document.body.style.overflow = 'auto'
document.body.removeEventListener("mousewheel", MouseWheelHandler, false);
document.body.removeEventListener("DOMMouseScroll", MouseWheelHandler, false);
}
Interesting links
I did a quick codepen example. See here
Also this article
Edit----------------
Also found this Stack Overflow question
I dont think that there is a pure JS way of disabling all scroll while still detecting scroll events from the user (just reread your question) that's why I think the overflow solution is the simplest/most elegant solution (that I could come up with).
You could always detect scroll the set the scroll position to the top with something like window.scroll(0,0) and/or window.scrollTo(0,0). From what I have tested it doesn't seem to work quite well.
Related
I have a site where I have each section as 100vh so it fills the height of the screen perfectly. The next step I wanted to implement was disabling the regular scrolling, and on scroll force the screen to jump smoothly to the top of the next 100vh section. Here is the example of this animation / feature:
https://www.quay.com.au/
I was having a hard time finding any answers for this as most things just deal with smooth scrolling when clicking on anchors, not actually forcing div relocation when the user scrolls up / down.
I just wanted to know what code I would need do this...
Thanks, been using stack overflow for a while but first post, let me know if there is anything I can do to make this more clear.
disclaimer: this solution needs some testing and probably a bit of improvements, but works for me
if you don't want to use a plugin and prefer a vanilla JavaScript solution I hacked together a small example how this can be achieved with JS features in the following codepen:
https://codepen.io/lehnerchristian/pen/QYPBbX
but the main part is:
function(e) {
console.log(e);
const delta = e.deltaY;
// check which direction we should scroll
if (delta > 0 && currentlyVisible.nextElementSibling) {
// scroll downwards
currentlyVisible = currentlyVisible.nextElementSibling;
} else if (delta < 0 && currentlyVisible.previousElementSibling) {
// scroll upwards
currentlyVisible = currentlyVisible.previousElementSibling;
} else {
return false;
}
// perform scroll
currentlyVisible.scrollIntoView({ behavior: 'smooth' });
e.preventDefault();
e.stopPropagation();
}
what it does is that it listens for the wheel event and then calls the callback, which intercepts the scroll event. inside the callback the direction is determined and then Element.scrollIntoView() is called to let the browser do the actual scrolling
check https://caniuse.com/#search=scrollintoview for browser support, if you're going for this solution
In all versions prior to iOS8, I was able to prevent the iPhone keyboard from pushing up (and destroying) my html/css/js view when the keyboard appeared by the following method:
$('input, select').focus(function(event) {
$(window).scrollTop(0);
// or via the scrollTo function
});
Since iOS8, this no longer works. One workaround is to place this code within a setTimeOut
setTimeout(function() { $(window).scrollTop(0); }, 0);
But it only makes the view do a jerky motion as the view is initially pushed up by iOS, then dragged back down by my js code. preventDefault and stopPropagation does not help either.
I've tried everything available on the web of course including my own solution posted here: How to prevent keyboard push up webview at iOS app using phonegap but so far, nothing works for iOS8. Any clever ideas on how to prevent the keyboard in iOS8 to push/move the view?
Try position:fixed on body, and/or wrap content in a div and position:fixed on it as well.
There are some options :
Make listener on your ios code, to move the screen up along with the keyboard height, so everything move up along with the keyboard, then your design save.
Make your css design responsive. Then no problem with change height, it will be scrollable inside your webview.
When keyboard pushes up view in iOS, a scroll event is triggered ($(window).scrollTop() is changed). You can put $(window).scrollTop(0) inside the scroll event handler. To prevent the jerky motion, set opacity to 0 during scrolling. Related codes may look like this:
function forceScrollTop() {
var scrollTop = $(window).scrollTop();
if (scrollTop != 0) {
$(window).scrollTop(0);
$(selector).css('opacity', 1);
$(window).off('scroll', forceScrollTop);
}
}
// when an input is focused ...
$(selector).css('opacity', 0);
$(window).on('scroll', forceScrollTop);
I have a phonegap application that uses iOS native scrolling through -webkit-overflow-scrolling in a div. I want to be able to manually halt an ongoing scroll when the user clicks a button (to scroll back to the top of the page). Is this doable?
This is actually very possible when using fastclick.js. The lib removes the 300ms click delay on mobile devices and enables event capturing during inertia/momentum scrolling.
After including fastclick and attaching it to the body element, my code to stop scrolling and go to the top looks like this:
scrollElement.style.overflow = 'hidden';
scrollElement.scrollTop = 0;
setTimeout(function() {
scrollElement.style.overflow = '';
}, 10);
The trick is to set overflow: hidden, which stops the inertia/momentum scrolling. Please see my fiddle for a full implementation of stop scrolling during inertia/momentum.
Unfortunately this is not possible at the moment. The scroll event is triggered only when the scrolling has come to an end. As long as the momentum keeps moving the content no events are fired at all. You can see this in Figure 6-1 The panning gesture in Apple's "Safari Web Content Guide".
I also created a fiddle to demonstrate this behavior. The scrollTop value is set after iOS is done animating.
You can capture a touch event using 'touchstart' instead of 'click', as the click event sometimes doesn't seem to get fired until the momentum scroll completes. Try this jQuery solution:
$('#yourTrigger').on('touchstart', function () {
var $div = $('.yourScrollableDiv');
if ($div.scrollTop() === 0) {
return false; //if no scroll needed, do nothing.
}
$div.addClass('scrolling'); //apply the overflow:hidden style with a class
$div.animate({
scrollTop: 0
}, 600, function () {
$div.removeClass('scrolling'); //scrolling has finished, remove overflow:hidden
});
}
where the 'scrolling' class simply has the CSS property, overflow:hidden, which as #Patrick-Rudolph said, will halt any momentum scrolling in progress.
.scrolling {
overflow: hidden;
}
Note: It's best to use a callback function to tell when your scroll animation finishes, rather than setting a timer function.
I have a script that monitors scrolling and takes control of the scrolling to animate the page based on certain parameters. To do this, it calls window.scrollTo(0, currentScrollTop); which perfectly interrupts the smooth scrolling in Firefox on Windows. I can then animate the page scroll to the place where I want it.
Unfortunately, this trick doesn't appear to work in browsers in MacOS which results in a broken experience as JavaScript and the browser compete to scroll the window.
Is there a cross-browser way to stop smooth scrolling with JavaScript?
Site using effect in question: http://capitalismis.com
Relevant (simplified) code:
$doc.on('scroll', function(e)
{
$doc.off('scroll');
window.scrollTo(0, $doc.scrollTop());
var aniSpeed = 1500 * Math.abs(scrollTop - selected.top) / windowHeight;
$body
.stop()
.animate({scrollTop: selected.top}, aniSpeed, 'easeOutQuad');
}
);
In short: don't try to override native scrolling. Every OS and device handles things differently and it's impossible to predict the different scenarios. There is "hard scrolling" (most Windows versions), "soft scrolling" (≈Mac OS X 10.6+) and browsers that only fire the onscroll event when the scrolling is completely done (iOS). It's a mess.
Instead of trying to modify the scrolling behavior of the body, I would modify the elements of the page accordingly. Listen to the onscroll-event, and move things around on the web page.
// Capture scroll event
$(window).scroll( function() {
// Get scroll offset from top
var scrollTop = $(window).scrollTop();
// Use it to move elements around on the page (or change backgrounds etc.)
// Here: move .element in the opposite direction of the scroll
$('.element').css({
'-vendor-transform' : 'translate3d(' + (scrollTop*(-1)) + 'px,0,0)'
});
});
Here's a frustrating problem. I use the following in script inside of a jQuery load block:
window.scrollBy(0,-100);
I do it because I set a div to be fixed at the top of the page through scrolling, and this line will compensate so that the anchor you've clicked to (http://page.html#foo) is seen where it should be.
It works great in Firefox. In Chrome and Safari, it doesn't, because the load event appears to happen before the browser scrolls to the anchor.
Any suggestions?
I came across into the same problem, and this is my work out. (A hack actually)
// Clicking on the navigation bar
$('.navbar-nav a').click(function(e) {
// Blocking default clicking event
e.preventDefault();
// Scroll to the anchored element with a delay
setTimeout(function() {$('#talks')[0].scrollIntoView();}, 5);
// Compensate the scrolling with another delay
setTimeout(function() {scrollBy(0, -$('#info').height())}, 10);
}
It seems like it's a Safari bug.
I also came across this problem. Using a timeout, even 0 ms, seems to work without visible jumping. Try this:
window.setTimeout()
{
window.scrollBy(0, -100);
}, 0);