alvarotrigo / fullPage.js

fullPage plugin by Alvaro Trigo. Create full screen pages fast and simple
http://alvarotrigo.com/fullPage/
GNU General Public License v3.0
35.24k stars 7.3k forks source link

Avoid accidental scrolling when reading content in the bottom of the slide when using scrollOverflow:true #941

Closed elahmo closed 2 years ago

elahmo commented 9 years ago

I am having one interesting behavior where some of the slides have content which is positioned at or near the bottom of the pages. So, on smaller screens where the content can't be shown all at once, when the user scrolls down to see the content, he or she might overscroll (via mouse or touch pad) and instead of just scrolling to see the content trigger the new page slide in as well, so the user can't read the content and has to go back.

One solution might be too change the content structure and add some padding or empty space below the actual content, but that seems like crude solution.

Is there a way to solve this so in the initial scroll, when the user is actually scrolling the page which has height larger than the screen/window height, doesn't trigger the scroll event?

Thanks

alvarotrigo commented 9 years ago

Already treated here and here. There's no solution for it yet.

I will keep this one open and close #294 as this one is better presented.

elahmo commented 9 years ago

Sorry for opening the already discussed issue. I did try to find similar issues but was overwhelmed with questions and didn't try that exact wording while searching.

Do you think its possible to solve this in this way:

The function I linked, _.debounce() has an interesting behavior that is applicable in this case. It would be triggered only after some time has passed after the scroll event has stopped, lets say some arbitrary three digit number of milliseconds, 300.

So, if a user gets to the page that is larger in height than the window height, the plugin would be disabled. While the user scrolls, nothing would happen, unless the end of the page is reached. After the end/bottom of the page is reached, and the scroll event has been stopped for some period of time, that would re-enable the plugin and in the next scroll event, the expected behavior for the user would be to go to the next slide. In case of continuous scroll from the top to the bottom of the active page, the plugin wouldn't activate and used would have to "pause" for a moment.

There would be no additional dependencies as the function doesn't use anything specific to underscore.js (more here).

alvarotrigo commented 9 years ago

The problem comes when dealing with Apple trackpads / trackpads in general and Apple Magic mouse. There scroll behaviour keeps firing even after 1 second depending on the acceleration of the scrolling.

I guess the way to go would be to force the user to reach the bottom, and then, after another scroll from the user, scroll the section. But the problem here is how we define the "2nd scrolling". As the scrolling event can be firing for 1 second after the user stops scrolling...

d13 commented 9 years ago

I actually added a debounce function into my local version a few weeks ago and am using it only on the MouseWheelHandler with a 50ms wait. It seems to handle the problem well.

Canubiz commented 9 years ago

@elahmo @alvarotrigo – I added some additional checks to the scrolling() function in my local version of fullpage.js to solve this issue in a project I am working on right now. Basically I am requiring users of my website to first scroll down to the bottom of a scrollable section, then stop there and wait for 750ms before scrolling again to move on to next section. Up until now, this seems like the most natural and intuitive behavior of visitors who want to read content at the bottom of a section. If you're interested, here is my modified scrolling() function (see //EXTRA CHECK… comments for my additions):

//EXTRA CHECK TO PREVENT EARLY SECTION SCROLLING
var lastScrollTime = 0;

function scrolling(type, scrollable){
    if (!isScrollAllowed[type]){
        return;
    }
    var check, scrollSection;

    if(type == 'down'){
        check = 'bottom';
        scrollSection = FP.moveSectionDown;
    }else{
        check = 'top';
        scrollSection = FP.moveSectionUp;
    }

    //EXTRA CHECK TO PREVENT EARLY SECTION SCROLLING
    var currentScrollTime = new Date().getTime();
    var lastScrollTimeDiff = currentScrollTime - lastScrollTime;
    lastScrollTime = currentScrollTime;

    if(scrollable.length > 0 ){
        //is the scrollbar at the start/end of the scroll?
        if(isScrolled(check, scrollable)){

            //EXTRA CHECK TO PREVENT EARLY SECTION SCROLLING
            if (lastScrollTimeDiff>750) {
                scrollSection();
            }
        }else{
            return true;
        }
    }else{
        // moved up/down
        scrollSection();
    }
}

What do you think? Does this also work for you? Is this a change that could make it into the next release of fullpage.js?

alvarotrigo commented 9 years ago

@Canubiz I think that might cause problems in devices with kinetic scrolling such as Apple track-pads. They might have difficulties scrolling down because of the scrolling inertia and they will have to stop scrolling for more than 750 milliseconds.

Canubiz commented 9 years ago

@alvarotrigo Thanks for your feedback. I developed this modification on a MacBook Air esp. testing its trackpad control and it seems to work exactly the way I'd expect to. I believe it's exactly the way scrolling on a fullpage website, including more content on a single section than it can fit, should behave: not scroll over that content at the bottom of a section, but stop there and require another, separate scroll attempt (detected but a short amount of time without any scroll events recognized) to move on to the next section. The value of 750ms is for sure something open for debate and fine tuning. I also tried with much lower values like 250ms and it still works very well, maybe even better…? So maybe, with a lower value we can still reach the purpose to stop over-scrolling scrollable section content but still serve visitors well who want to quickly jump to the next section. Note: this modification does not influence scrolling behavior of sections without scrollable content inside them. So in conclusion, if one does not have scrollable sections, this should change nothing in user experience. On the other hand, if one uses scrollable sections, user experience dramatically improves, at least from my point of view, as users cannot easily over scroll any content they wanted to go to and read. I will do some more testing with the separate Apple Magic Trackpad and the Magic Mouse as well as trackpads on some other Mac models from friends and family and will come back with results, if you're interested. :)

alvarotrigo commented 9 years ago

Could you provide a link where I can test it? I still thinking that it will cause problems when swiping fast repeatedly, but I'll give it a try.

Canubiz commented 9 years ago

Sure, you can check it out here: http://polecious.at/studio/_betterscrolling/ (It's now using the 250ms value.)

elahmo commented 9 years ago

@Canubiz Thanks for your efforts. I tested this on my iPad, and the scrolling works but the kinetic effect is no longer there, meaning as soon as a lift my finger, the scrolling on the portions that should be scrolled stops. This is a bit counterintuitive, since most of the users usualy "flick" on tablets and expect the page to continue with that inertia, so that part is a bummer...

But that might have nothing to do with your code, since I think I noticed this as well when testing stuff before on my version as well...

Canubiz commented 9 years ago

@elahmo Thanks for checking out my modification!

Indeed, I believe the lack of inertia is because the Slimscroll.js framework being used here doesn't support it at all. So, please correct me if wrong, but I think the lack of inertia when scrolling within a section should also be present in the original examples provided with the fullpage.js project.

There even is an issue thread here discussing if it's possible to use iScroll instead of slimscroll framework to improve the way scrolling looks and feels: #623

MuTLY commented 9 years ago

Instead of using Slimscroll.js for the parts that exceed the height of the slide panel, why don't you just use, say, a <DIV> with 'overscroll: auto'?

I know the scrollbars won't be as nice as Slimscroll.js's, but I think that would solve the inertia problem on mobile, right? So maybe check if it's a mobile device and just go with 'overflow: auto', if not, use Slimscroll.js.

alvarotrigo commented 9 years ago

Instead of using Slimscroll.js for the parts that exceed the height of the slide panel, why don't you just use, say, a

with 'overscroll: auto'?

You can, but it won't work at all in touch devices plus the scrolling bar looks a bit ugly :)

I would encourage you to try iScroll.js. fullPage.js is not adopting it at the moment because it doesn't provide compatibility with IE 9.

Canubiz commented 9 years ago

@MuTLY - I assume you mean "overflow" not "overscroll", right? According to CSS scrolling with momentum using this property should actually work, however at least on iOS. Not sure about other touch devices. This would be the code required according to https://css-tricks.com/snippets/css/momentum-scrolling-on-ios-overflow-elements/ (have not yet checked though):

overflow-y: scroll; /* has to be scroll, not auto */
-webkit-overflow-scrolling: touch;
MuTLY commented 9 years ago

@Canubiz yes, my bad, I was talking about 'overflow: auto', in fact your example is exactly what I meant. I believe mobile devices do use the 'momentum' with the CSS mentioned, and I know for sure that Windows Phone 8 uses that (along with iOS and the -webkit- prefix).

Not sure about Android, but I think it goes the same way. So maybe a solution would be to check if there's 'movement' on the scrolling (swipe), say check for X milliseconds if the scrollTop changes. If it doesn't change then we reached the end of that DIV with overflow and now we call the method to advance to the next slide (up or down).

@alvarotrigo I did use iScroll on some projects and it behaves bad on some Windows Phones, so I had to change my mind about presenting cool scrollbars to the user OR presenting them a better scrolling experience. Turns out I had to switch off iScroll on this case and only use it on other devices. As for the scrolling itself, it worked without problems with just the 'overflow:auto' CSS for the Windows phones.

In my opinion, the user, on a mobile device, rarely, and I mean RARELY uses scrollbars to navigate up and down / left and right on web pages and/or apps. The scrollbars don't even show up on some devices, so why should I bother? :)

alvarotrigo commented 9 years ago

@MuTLY many people like to have the scroll bar in a side, not as an input element to scroll up or down, but as a way to tell the user they can keep scrolling down. More an issue of user experience and accessibility in this case.

Using overflow:scroll won't show an scroll bar.

reddo commented 8 years ago

I've tried @Canubiz's solution and it's not working with the current version :(

Scroll isn't working at all, sections don't change. Clicking on nav works though.

alvarotrigo commented 8 years ago

@reddo the issue still open, there's no proper solution for it.

reddo commented 8 years ago

@alvarotrigo have you considered using a different plugin instead of sclimscroll? Maybe jQuery custom content scroller or TinyScrollbar?

alvarotrigo commented 8 years ago

@reddo I have, but the solution doesn't seem perfect. Take a look at this topic. The changes were commited to the DEV branch. You can try to create a module for any other plugin, but right now it is using slimScroll and you have the gist for iScroll.js here.

reddo commented 8 years ago

Gave it a try and it seems to work fine. I've also tried with ie9 and I didn't see a problem. I don't need support for ie8, so that shouldn't be an issue.

alvarotrigo commented 8 years ago

@reddo the scroll bar just doesn't look as nice as it's the default one for Windows machines.

pinipints commented 8 years ago

@reddo can you please share your code/approach on integrating iscroll in full page.js Thanks in advance

reddo commented 8 years ago

@pinipints I've just followed @alvarotrigo's instructions 3 posts up. I did have to make some small edits to the linked gist code though. I'de be more than glad to share that code, if you want.

Basically I downloaded the fullpage.js from the dev branch linked, included the modified code from the gist and it just worked.

alvarotrigo commented 8 years ago

@pinipints @reddo the branch is no longer necessary. It was merged yesterday with the main project.

Here you have a demo online using iScroll.js. You will only need to place this code at the bottom of fullpage.js code, just before the closing brackets. As it is here.

reddo commented 8 years ago

@alvarotrigo I still had to change bits of the gist code, specifically lines 36 and 37 have some variables defined with let, I had to change those to var otherwise my uglify task threw an error.

alvarotrigo commented 8 years ago

@reddo don't know about uglify, but the gist I just posted works as you can see on the demo page I linked. In any case, I would also change that to var as you said.

pinipints commented 8 years ago

@reddo i get errors on safari and firefox due to the variables defined with let while on google chrome it loads fine. @alvarotrigo thanks for having that demo page with iscroll. changing the let with var may help making it compatible with all browsers i will give it a try today, thanks once again

reddo commented 8 years ago

@pinipints I changed let to var on lines 36 and 37 of the gist and it worked just fine. Good luck

pinipints commented 8 years ago

@reddo yes thanks.. same, i changed let to var and it worked for me on all browsers. thanks once again for all the help :)

0xadri commented 8 years ago

What about triggering the scroll to the next section only if a good part (let's they at least 1/3rd) of the viewport is on the next section?

This solution should be easy enough to implement. And one could provide a new option parameter to let the dev choose what value works better (1/3rd might not be optimal for every use case).

alvarotrigo commented 8 years ago

This solution should be easy enough to implement.

You can create a pull request for it.

0xadri commented 8 years ago

Yeah, I will try to implement it and create PR if I am successful

choujar commented 8 years ago

@adrien-be did you have any luck with it?

0xadri commented 8 years ago

I didn't get the chance to implement this actually as I ran in other unrelated ux issues. I hope you manage to do this.

On Tuesday, 5 April 2016, Sahil Choujar notifications@github.com wrote:

@adrien-be https://github.com/adrien-be did you have any luck with it?

— You are receiving this because you were mentioned. Reply to this email directly or view it on GitHub https://github.com/alvarotrigo/fullPage.js/issues/941#issuecomment-205772684

rbosneag commented 8 years ago

After the switch to iScroll it seems that on iOS 9.3.2/iPhone 6S this is not an issue anymore! I still have issues though on OSX (Chrome, Safari and Firefox). I wonder why this happens, usually it's the other way around (working on desktop but not on mobile)

reddo commented 7 years ago

I'm trying a different approach right now and it seems to be working. Here's my scrolling function at the moment: gist - had to add a gist, my code kep getting messed up.

I started from @Canubiz's idea. This method stops the scrolling for 250ms once you hit the bottom of the div for the 1st time, resets the variable and you can scroll on the next time.

alvarotrigo commented 7 years ago

This method stops the scrolling for 250ms once you hit the bottom of the div for the 1st time, resets the variable and you can scroll on the next time.

Looks like you'll have problems with kinetic scrolling (Apple trackpads, magic mouse...)

reddo commented 7 years ago

It's working fine on my macbook for the time, I'll keep testing to check if it's viable long-time. I'll tweak the timeout a bit to see what's best.

alvarotrigo commented 7 years ago

@reddo try scrolling fast, then waiting 250 milliseconds (just a bit) and then try scrolling fast again. The scrolling inertia should should keep firing scrolling events for more than 250 milliseconds and, if the inertial scrolling is accelerating (this is an improvement since the topic was opened), then you should be stuck in the section until the inertia stops.

alvarotrigo commented 7 years ago

@reddo by the way, shouldn't you be clearing your timeout? Otherwise what you are getting is just a delayed scrolling, but that will take place even after the smallest scrolling, like it happens now.

reddo commented 7 years ago

I've updated the gist to account for scrolling direction ad increased the timeout a bit and added some comments: (see gist).

@alvarotrigo It really is working good, even using my trackpad (MacBook Pro Retina, 13-inch, Early 2015; with latest OsX and Chrome).

I don't clear the timeout because I want the page to scroll to the next section if the user keeps scrolling. I'm not saying this is the best solution, but I just wanted to share in case I can help someone else.

db-24 commented 7 years ago

@reddo really interesting conversation, I too am requiring a solution to this scrolling issue. I'd like to test the gist you've amended. Could you advise on usage as i'm not proficient in js - am I supposed to copy the gist and replace the corresponding section in the jquery.fullPage.js file??

... I have tried this but it kills the scrolling completely except when using the nav buttons...

@alvarotrigo are you in support of the gist or are you still seeing potential issues?

Thanks,

alvarotrigo commented 7 years ago

@db-24 I haven't tested it myself. So I can not say much. But I do not see any clearTimeout, which means the timeout will always get fired no matter what the action of the user is. As it will always enter in the timeout the 1st time it reaches the top or the bottom.

My guess is, kinetic scrolling will keep firing mousewheel events that will kept being caught by the scrolling function (unless they are of less intensity the the previous ones average) and therefore this gist will only cause a 500 milliseconds delay, but will keep scrolling up or down when reaching the top or bottom with a single swipe in a Mac trackpad (or similar)

To test it. I suggest a fast but single swipe in the trackpad / magic mouse when you are about to reach the end of the scrollable section.

reddo commented 7 years ago

@db-24: I'm using it successfully in a project without any issues. Let me see if it's the latest version, but I haven't had any problems with it so far whenever I updated the fullpage.js (I'm currently using the dev version). You just have to replace the function in the fullpage.js with the same name (currently from here: https://github.com/alvarotrigo/fullPage.js/blob/master/jquery.fullPage.js#L1068 to line 1086)

@alvarotrigo: That is how I intended it. It should keep scrolling after the 500ms; I added that timeout just so I stop accidental scrolling, I still want to be able to scroll to the whole page if I want to, I don't want to have to stop after each section and start scrolling again, but I already explained this. Maybe someone needs it different, but right now it suits my needs perfectly.

alvarotrigo commented 7 years ago

That is how I intended it. It should keep scrolling after the 500ms; I added that timeout just so I stop accidental scrolling

That means, you are not actually stopping accidental scrollings. You are just delaying them 500 ms no matter if it was by accident or not.

reddo commented 7 years ago

I'm not trying to stop scrolling in any way, I'm just stopping the user to accidentally switch sections

As of now, it is really hard to stop on the bottom of a section and not scroll over, that's what this hack fixes. I don't know if I can explain any clearer.

reddo commented 7 years ago

@db-24: maybe your issue is related to #2353 - it's fixed on dev. I'm using dev version and it's working fine.

db-24 commented 7 years ago

Thank you both for getting back to me. fullPage.js is excellent, my clients only gripe was the scrolling at the end of scrollable slides.

@reddo Thank you. It's exactly what I hoped it would be! Allows just enough to be able to hit the top or bottom of the slide (admittedly on slower scrolling) before pushing forward and continuing (with magic mouse). Excellent.

lanbomo commented 7 years ago

Thanks for fullPage.js, it's a awesome plugin. I also get the problem when use it.

And I try to improve the case, now I get a effect than which I need, and I wanner contribute it to help others.

So I wanner start a Pull Request. Before I do that, I found the issue about the problem, and I realized it have another problem with trackpad and Magic Mouse.

I have not found a perfect way to solve this, but in my way, it can set the delay attribute to weaken the problem with Mac trackpad and Magic Mouse I guess.

I have got a good effect on my PC (Windows7) and mobilephone (Android 4.4), if someone have the MacBook and iPhone|iPad, please test it. On the demo, I introduced a infomation with the solution.

https://lanbomo.github.io/fullPage.js/examples/scrollOverflowEndPrevent.html

I put the demo on my github pages, someone can test it, if you wanner to use with your page, you can download the jquery.fullPage.js file on my fork repositorie with dev branch.

https://github.com/lanbomo/fullPage.js/tree/dev

@alvarotrigo If you think this is a well solution to the problem, please consider to merge it, and I will start a Pull Request. Thanks for your works.