JavaScript scroll based animation is choppy on mobile - javascript

I have 2 divs (left and right) and i want to scroll the left based on the right.
https://jsfiddle.net/3jdsazhg/2/
This works fine on desktop, but when i change to mobile, it's not smooth anymore...
This can be noticed very easily, by changing
_left.style.top = _content.scrollTop - (_content.scrollTop * ratioLeftRight) + 'px';
to
_left.style.top = _content.scrollTop + 'px';
Where it should act as a fixed positioned div
I would like to know the exact reason why this isn't smooth... I know that it's not the animation. Simple animation on the div is smooth, the issue comes up when it's based on scroll.
How can i make this animation smooth?

It's probably choppy because it's being fired ALOT when being scrolled, in fact i'm pretty sure IOS mobile pauses the javascript execution whilst the user is scrolling.
Instead I'd suggest using an interval, you could tweak the time between each interval to what feels good for your use-case.
Although it may seem intensive that it's firing this logic every X millisecond when using the scroll event you could be firing the event off hundreds of times per second, which is going to be far more intensive and noticeable to a user using a device with limit processing power.
(function () {
var interval = null,
//Currently set at 0.4 seconds, play with the code
//and change this value to see what works best for
//this use-case
time_between_interval = 400;
setInterval(scrollLogic, time_between_interval);
function scrollLogic () {
//The function body of what you're assigning
//to the scroll event.
}
//I have omitted clearing the interval but you would want to do that, perhaps on page change, or something.
//clearInterval(interval);
})();

I finally managed to think out a solution.
From my point of view, i'm guessing the mobile view fires the scroll event less often and because we are scrolling the wrapper, we first scroll the whole page and then scroll back with js the left part and because it's different from the desktop version, this issue becomes visible...
The solution was to change the left side to fixed position, and substract from the top instead of adding to it.
_left.style.top = -(_content.scrollTop * ratioLeftRight) + 'px';

Related

Using ScrollY on iOS gives strange values after bounce on bottom

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.

Item positioning on scroll gives a warning about asynchronous scrolling

I'm trying to position two images by changing their top margin based on the scroll position.
The margins have a max value as well.
Everything works just fine but I have a warning on the console, saying that this solution can cause a jittery scrolling effect in browsers with asynchronous scrolling.
My first question is, should I worry about this?
Also, this is literally my first few lines of javascript and I'm not sure if this solution is good enough, so any advice is appreciated.
It just looks so simple I feel like there is a catch.
I could do it by adding classes to the images and set the margins in CSS, but it would be a lot longer code I guess.
I'm trying to do this strictly with js and CSS grid, just to learn to solve problems with limited tools.
The images are in a div, which is in a grid cell.
window.addEventListener("scroll", function () {
myMargin = 0.011 * window.scrollY;
if (myMargin < 3.4) { //max margin is 3.4% for myImg1
myImg1.style.marginTop = animMargin + "%";
myImg2.style.marginTop = animMargin / 2.7 + "%"; //myImg2 moves on a different scale
} else {
myImg1.style.marginTop = "3.4%"; //when the max value reached the margin is fixed
myImg2.style.marginTop = "1.25%";
}
});
Scrolling handlers can be intensive and put performance strain on the page as they will fire far more times than your handler actually needs. This ends up causing choppy/lag when scrolling as the browser may need to repaint in response to your handler.
A common technique is to throttle or debouce the handler.
Throttle:
only invokes func at most once per every x milliseconds.
Debouce:
delays invoking func until after x milliseconds have elapsed since the last time the debounced function was invoked.
The warning you are getting is actually fine, but you may benefit from using a throttled callback and increase the wait time to the max that is suitable for your needs - so least times it is called in order for it to work for you.
Demo using lodash throttle
// only call the handler once every 200ms
const throttledScroll = _.throttle(() => {
console.info('throttled', window.scrollY);
}, 200);
window.addEventListener('scroll', throttledScroll);
html,
body {
height: 300vh;
}
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.15/lodash.min.js"></script>

iOS Safari Overscrolling: Pulling down vs. bouncing

My team and me are developing a web application which bears a fixed header, that doesn't scroll.
In order to handle overscrolling on iOS, we need to detect scrolling in negative direction and reposition the fixed header as static again to make it scroll along with the rest of the page.We do this by binding a jQuery scroll handler to window:
$(window).scroll(function() {
if ($(window).scrollTop() < 0) {
// position static header postioning in order
// let the header behave correctly when overscrolling
}
});
This works well, when the page is manually pulled (dragged) down.
But as every iOS user knows, when scrolling the page from a downwards position with speed up again, it bounces (overscrolls), once it reaches its top.
In this case, our scroll handling doesn't work.
At the moment I can imagine two reasons, why this different behaviour occurs:
Rapid scrolling upwards, and making a page bounce, is too fast for Safari's JS engine to ensure a fluid handling
Is bouncing when scrolling upwards technically the same as manually pulling down a webpage? In respect to $(window).scrollTop() ?
Has anybody some hints how to make my scroll handling work in both cases?
If position:fixed in CSS isn't working for you, then you should try to make a draw loop, and every single time that loop runs, you place a horizontal offset that is equal to how far your user has scrolled.
Basically, your JS should look like this if CSS doesn't work:
var head = document.getElementById("header");
//head now has our header
head.style.position = "relative";
//and now, we can manipulate it's position
function draw(){
head.style.top = window.pageYOffset;
//all that's left to do is do this each and every frame.
}
And if you don't know how to make a draw loop, here's the code:
var frameRate = 60;
var frameCounter = (function(){
var counter = 0;
return function(){
counter ++;
if(counter > frameRate/1000){
counter -= frameRate/1000;
draw();
}
}
})();
setInterval(frameCounter, 1);
This has been resolved in iOS 9.3 New meta tag option
<meta name="viewport"content="width=device-width,shrink-to-fit=no">

Scroll window without a jump (javascript or hashtag)

I want a solution either using a hashtag pointing at the name of an anchor tag or javascript.
The javascript I am currently using looks like this window.scroll(0, 20000);. The problem is that this causes the window jerk down when a user arrives on the page.
I know there are jQuery animations that make this movement more gradual. However, what I want is something that makes the movement of the window imperceptible to the user. I want to be as if the user landed at the bottom of the page.
The problem you face is that you wish to go to the bottom of your page which has not loaded yet. I would consider loading the page in a hidden format then show it when it has all loaded and after scrolling the user at the location you want. Use the focus or scroll to methods.
Take a look at the filament group website.
http://filamentgroup.com/
they hide the page with a loading screen until it is ready.
This way there is no jerk.
Hope this helps.
In loop it works, if the page is fully loaded and shown:
for(var n=0;n<1000;n++) window.scrollBy(0,20);
(Notice that 20*1000=20000, which was the original place to scroll.)
Teemu's answer doesn't seem to work for me (it goes straight to the bottom, making the loop with scrollBy stepping invisible), because it doesn't implement a delay.
If you mean to animate from top to bottom of the page in a 1000ms, try something more like this:
for (var n = 0; n < 1000; n += 1) {
setTimeout(function () {
window.scrollBy(0, document.height / 1000);
}, n);
}
That will give a 1 second (1000ms) animation, scrolling to the bottom in roughly 1000 steps.

jQuery div autoscroll

I am looking for advice on how to create an autoscrolling effect using jQuery which would enable an entire div within a page to begin scrolling vertically upon loading at a constant slow speed. This would be a div with a large amount of content of which only a small amount was visible on the screen at any one time.
The scroll needs to be automatic, smooth and at a defined rate for example 10 pixels per second. Additionally when the scroll gets to the bottom of the page I need to be able to call a function.
I have tried a few different jQuery plugins but found nothing yet that worked reliably. Can anybody suggest an approach to take here?
Thanks
Simon
This can easily be done without jquery.
function init() {
var div = document.getElementById("myDiv");
// increase the scroll position by 10 px every 10th of a second
setInterval(function() {
// make sure it's not at the bottom
if (div.scrollTop < div.scrollHeight - div.clientHeight)
div.scrollTop += 10; // move down
}, 100); // 100 milliseconds
}
Try this technique
try this plugin : scrollTo
especially the onAfter

Categories