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)'
});
});
Related
I am using the window.scrollY event listener to get the scroll amount on my page and I set an animatino fram accordingly:
scroll = window.scrollY //inside the event listener
...
function animationLoop() {
...
scrollRatio = scroll/window.innerHeight
animMixer.setTime(scrollRatio) // every page is a "second"
...
}
This works wonderfully on the desktop, and also on iOS on the first scroll forward through the page. But as soon as the page bounces at the end, the scroll value seems to jump around unnecessarily, ie there is a mismatch between the position in the webpage and the animation frame. The timing is off until I scroll back to the very top of the page. After that the downward scrolling works fine again.
What happens to the scrollY value after bounce? I can't figure out where the problem is. I've tried things like pageYOffset but the problem remains. Also the value of the scrollRatio is clamped.
I know that there are some issues with the bouncy behavior of webpages on iOS, but these are negative values at the top of the page.
Thanks for any pointers.
I needed JavaScript for automatic scroll down in a smooth/slow manner.
I have a form with many radio buttons which is quite similar to survey form.
I used script from the below mentioned link. This link works fine smoothly for scrolling downwards.
But problem comes when you reach the bottom of page and cannot scroll upwards.
I am not so good in JavaScript. Does anyone here has solution or fix to this?
Link to Stack Overflow thread:
Slow down onclick window.scrollBy
function scrollByRate(y, rate)
{
//calculate the scroll height
var scrolling = Math.max( document.getElementsByTagName('html')[0].scrollTop, document.body.scrollTop);
//save the old value as "static" var
arguments.callee.tmp = arguments.callee.tmp || scrolling + y;
//make a little scrolling step
window.scrollBy(0, (arguments.callee.tmp - scrolling) / rate);
//are we arrived? if no, keep going recursively, else reset the static var
if(arguments.callee.tmp - scrolling > 100) setTimeout(function() { scrollByRate(y, rate); }, 10);
else arguments.callee.tmp = undefined;
}
Scrolling down slowly
I can see your approach having a negative impact on performance. It looks like the browser will block until the target scroll destination has been reached.
My suggestion is to use what is out there for smooth scrolling already. The scrollTo method of any scrollable pane (e.g. window object but also a scrollable div for example) has a "behavior" property that you can set to "smooth", e.g.:
window.scrollTo({
top: 100,
left: 100,
behavior: 'smooth'
});
Keep in mind that the compatibility at the time of writing is limited to Chrome, Firefox, Edge and Opera which means you'll have problems on Internet Explorer and Safari (so all Apple products). I myself use a polyfill to get the smooth scrolling back on my application, this one in particular: https://github.com/iamdustan/smoothscroll
This question is for when using the mouse wheel on an external mouse, not the touchpad.
I'm working on a program that modifies the mouse's behavior.
I'm using window.scrollBy, but window.scroll or window.scrollTo or something else could also work.
I've included the code below for a test page that you could copy and paste.
It works fine for one scroll, but not for multiple scrolls at once.
One scroll of the mouse wheel scrolls smoothly up or down.
But when multiple scrolls are sent quickly, the page actually scrolls slower in a jerky motion.
The problem seems to be that before the initial scroll is finished, the next scroll interrupts it.
For example in the code I typed out below:
If you scroll slowly down 5 times, then quickly up 10 times, the page doesn't scroll back up to the top.
It makes me wonder how it works normally in Windows or Chrome OS or other operating systems.
I've tried to research this already but couldn't find a good explanation of how it normally works.
Normally multiple scrolls at once increase the scrolling smoothly, while the code below does not.
How does this normally work?
What code can be used to make the page scroll properly?
<html><head>
<title>Scroll Test</title>
<script>
window.addEventListener("mousewheel", processEvent, {passive: false});
function processEvent()
{
event.preventDefault();
var scrollAmount = event.deltaY < 0 ? -100 : 100;
window.scrollBy({left:0, top:scrollAmount, behavior:"smooth"});
}
</script>
</head><body align="center">
<b>Test Area:</b>
<p>
</body></html>
<script>
for (var i = 1; i <= 1000; i++) {document.body.innerHTML += i + "<br>";}
</script>
Either throttle the mousewheel/wheel event using something like lodash:
window.addEventListener("mousewheel", _.debounce(processEvent, 500), {passive: false});
Another thing to note, the window scrollBy function may not be as smooth a scroll as the GSAP ScrollTo plugin:
gsap.to(window, {duration: 2, scrollTo: 400});
Some potential solutions depending on if you're cool with external libraries! :)
I'm working on a web project that has animations and page changes on the scroll ( specifically, scroll direction ) and I've been looking for multiple possible good and reliable solutions.
I've been detecting the scroll direction by detected the window's scrollY with the user's previously saved scrollY that I have saved in a variable. The only problem is that the scroll event doesn't fire when at the top or the bottom of page, even though the content is all absolute/fixed positioned.
I want to turn to the wheel event because of its deltaY values from the event, and it still fires when at the top of bottom of the page so I can remove the scrollbar and keep the body of the page 100vh.
The Mozilla dev docs say:
Don't confuse the wheel event with the scroll event. The default
action of a wheel event is implementation-specific, and doesn't
necessarily dispatch a scroll event. Even when it does, the delta*
values in the wheel event don't necessarily reflect the content's
scrolling direction. Therefore, do not rely on the wheel event's
delta* properties to get the scrolling direction. Instead, detect
value changes of scrollLeft and scrollTop of the target in the scroll
event.
(https://developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event)
And I'm also curious if the wheel event will work correctly on mobile with touch?
Here's a good example of what I'm trying to replicate: https://reed.be
There is no scrollbar, yet things still happen based on your scrolling.
CanIuse shows full compatibility of the wheel event with modern browsers, and some older versions.
see here -> https://caniuse.com/#feat=mdn-api_wheelevent
I've found a solution that references the wheel event (How to determine scroll direction without actually scrolling), though my question still applies -
How reliable is the wheel event across devices and browsers, including mobile?
I am limited to my own current version browsers and android devices for testing.
You can fool the browser by setting the additional height on the body to match the content width and setting the overflow to scroll. Then use some basic script, to set the scrollLeft property of your container to equal the window scrollY.
You will need to set the height of the body equal to the total width of the panels.
body {
height: 400vh; // 4 panels of 100vw each
...
}
.panel {
width: 100vw;
...
}
JS
const viewPort = document.querySelector('#viewport');
let lastScroll = 0;
window.addEventListener('scroll', (e) => {
let scrollY = window.scrollY;
// scroll the container by and equal amount of your window scroll
viewPort.scrollLeft = scrollY;
lastScroll = scrollY;
});
Rough JSFiddle Demo
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);