How do you resolve scrollTo stutter on iPhones? - javascript

I am using a Muuri grid with draggable items. On desktop, users can use the mousewheel to scroll; however, I had to add an event handler to check if the user holds the item for x time, then they can drag the item. If they immediately move a certain distance, it prevents dragging and programmatically scrolls the view with window.scrollTo.
This works fine on Android and Windows touch screens but the screen jumps around on iPhones. Worse on Safari but still occurs on Chrome. I tried using webkit style atrributes that some articles mention for smoother scrolling, used different scroll behaviors, made sure calculations lead to a top, whole number value (only setting top) of 0 or higher, and the only thing that made a difference was setting a delay. A higher delay (100ms) between scrollTo calls seems to resolve it but isn't smooth to the user.
Content for the move event is simply the method call:
window.scrollTo({top: initialTop + yStart - yEnd})

Related

How to stop Webkit native scroll momentum after disabling and re-enabling scroll

I have a tricky problem with Webkit browsers and some custom scrolling behaviour.
On my page, I am detecting scroll, and when it happens, disable the scroll by making the body have overflow:hidden and then do some custom animation logic for the scroll position.
The problem on Webkit browsers (Mac OS) is when I re-enable scroll the native scroll seems to still be easing out, thus moving the page some more in the direction of the initial scroll event, which is undesirable in this case.
Is there a way to disable/reset native scroll or native scroll momentum?
Here is a codepen illustrating the problem. HOWEVER you need to download it as zip and run locally — whatever codepen is doing to the preview container prevents the "native" scroll that is causing the issue. When viewing locally and scrolling "down" what you should see in:
Firefox (the desired behaviour): For 25 frames after the scroll, the scroll position should not move, the page background should be beige. Only when scrolling again should the page animate again
Webkit: After 25 frames after the scroll, you'll see the page flicker white when the animation timeout finishes, and without scrolling anew the "old" native scroll easing seems to still be "ramping down", which triggers the scroll event, and immediately paints the page background beige again. I'd like to avoid this "old native scroll" triggering after I reenable the scrolling.
The solution was to use a different element than body as scroll wrapper. Apparently this behaviour of "resuming" momentum scrolling when re-formatting the body to be scrollable (have overflow) is hard-coded, whereas other scrollable elements do not exhibit this unpredictable side-effect.

scrollIntoView with smooth behavior not working in chrome when raised by wheel event

It's a bit tricky to explain, so maybe the easiest way to understand the problem is to go to the site web and compare the behavior between Firefox (working perfectly as expected) and chrome (scrollIntoView is not working).
Basically, I have a left column menu but I didn't wanted to put a position: fixed so it's a relative one with a float. So the scroll for the main content is with overflow-y on .
Now, I have a "welcome" image which takes all the screen height of the visitor. The behavior I created is when the visitor scroll down, it goes straight to the end of the image. And when the visitor is just below the image and scroll a bit up, it goes directly to the top of the image. Apart from that, the scroll in the text works ordinary.
Everything is working fine with Firefox but Chrome is not scrolling into view as expected. See the scroll.js file in the website linked above, console.log shows that chrome is catching the wheel event and entering scrollIntoView but doesn't scroll.
Is that a bug in chrome that I should report?
thanks
You have to look at the WheelEvent.deltaMode value to know how the brwoser is reporting the wheel event:
WheelEvent.deltaMode
Read only
Returns an unsigned long representing the unit of the delta values scroll amount. Permitted values are:
Constant Value Description
DOM_DELTA_PIXEL 0x00 The delta values are specified in pixels.
DOM_DELTA_LINE 0x01 The delta values are specified in lines.
DOM_DELTA_PAGE 0x02 The delta values are specified in pages.
A good library to standardize the wheel events across browsers is https://github.com/basilfx/normalize-wheel

Smoothing Page Offset Values During On Scroll Event

I'm working on a parallax effect for a project and while I have all the animation working great the scroll-driven effect often appears to stutter depending on the input device.
I've ended up using Request Animation Frame (RAF) to check the page offset every animation loop instead of using the basic `.scroll() event for performance reasons. However using either, if I log out the offset/scroll position values the events receive they are often very far apart for a scroll wheel/ball versus a track pad. Because the animation is scroll/offset driven this causes stuttering.
For instance a track pad triggers many events with only a few pixels difference between each event's offset value while a scroll wheel/ball triggers fewer events with 5-15 pixels difference (depending on the scroll speed) leading to a less smooth animation.
You can fool around with this yourself on this guys fiddle that goes like this:
$(window).scroll(example);
function example() {
var tempScrollTop = $(window).scrollTop();
console.log("Scroll from Top: " + tempScrollTop.toString());
};
Anyone know a good library or method for smoothing out these scroll events and their offsets? I know it's possible because I've seen parallax sites where the animations are nice and smooth regardless of input but I can't figure out how it's managed. Thanks.

.scrollTop position of scrollable element cached by UIWebView with overflow scrolling

I am currently developing a hybrid mobile app which makes use of -webkit-overflow-scrolling: touch; on the "content area" to provide smooth scrolling.
I have hit somewhat of a road block however when using this feature. Upon scroll (I check with an .onAnimationFrame loop) I check the .scrollTop position to see if any movement has occured so that I can let various components within the application know of this so they can perform certain actions (Use case examples may be parallax scrolling, controlling culled rendering etc.). This is all well and good when testing in a desktop browser (Ie. Chrome 41) however when debugging within iOS Safari OR iOS UIWebView the scrollTop position seems to be cached when there is a large amount of movement (Eg. a user flicking the view)
This caching means that other elements expecting to know the exact current scrollTop value will fall behind and the view becomes out of sync.
My presumption is that overflow scrolling forces rendering onto the gpu so I'm wondering if there is any way to get around this or to force invalidation of the cached scrollTop value.
DEMONSTRATION: http://jsfiddle.net/skpmkjea/ (load up in safari on an ios device and connect to debugger to see console log of scroll top positions)
Things I've tried:
Forcing an empty element in and out of the root body to try and force a full page update to re-calculate the scrollTop value
Using a container div within the scroll element and checking for the bounding box updating .getBoundingClientRect() but this seems to have the same cached values
More info (I'll add more if it would help anyone):
UIWebView build with Cordova
My main test target is iOS7
The issue exists but is much less noticeable (ie. cached value invalidation appears to occur at intervals) on android 4

Android browser touchend event bug workaround

I've been developing a mobile site for my homepage and I have run into an issue when hooking into mobile touchevents. Basically I would like to accomplish the following:
User scrolls down
on touchend event is fired --> a function is called to figure out the amount of the document that is hidden above after the scroll (like jQuery scrollTop)
program takes action based on the amount of the document that is hidden up top
My issues are the following. So touchend works like expected in iOS, when the user lifts her finger the function makes a call to jQuery.scrollTop() which gives me a pixel value for how much the user has scrolled down. However on Android Browser devices it seems that the jQuery.scrollTop() value is calculated on touchstart. That is to say the event doesn't fire off properly, I get the correct pageX & Y coordinates from the touchend event, however scrolltop() returns the value from when the user started scrolling. I've checked around on the inet and this seems to be a known android browser bug, what I want to know is if there a decent workaround for this issue i.e. one that doesn't involve preventing the default scroll behaviour!? Thanks in advance!
Are you taking into account smooth scrolling? or just basic scrolling?
With basic scrolling you should be able to get the correct value simply by using document.body.scrollTop
Let me know if there is an issue

Categories

Resources