Code Monkey home page Code Monkey logo

inobounce's Introduction

iNoBounce

Stop your iOS webapp from bouncing around when scrolling

The problem

You've built a nice full-screen mobile webapp, complete with scrollable elements using the -webkit-overflow-scrolling property. Everything is great, however, when you scroll to the top or bottom of your scrollable element, the window exhibits rubber band-like behavior, revealing a gray tweed pattern. Sometimes, your scrollable element doesn't scroll at all, but the window still insists on bouncing around.

The solution

No dependencies, no configuration, just include iNoBounce.

<script src="inobounce.js"></script>

Example

All you need is an element with height or max-height, overflow: auto and -webkit-overflow-scrolling: touch.

<script src="inobounce.js"></script>

<style>
    ul {
        height: 115px;
        border: 1px solid gray;
        overflow: auto;
        -webkit-overflow-scrolling: touch;
    }
</style>

<ul>
    <li>List Item 1</li>
    <li>List Item 2</li>
    <li>List Item 3</li>
    <li>List Item 4</li>
    <li>List Item 5</li>
    <li>List Item 6</li>
    <li>List Item 7</li>
    <li>List Item 8</li>
    <li>List Item 9</li>
    <li>List Item 10</li>
</ul>

See the examples/ folder for more examples, including a full-screen list, a canvas drawing app, and a fully skinned iOS-style app.

API

Loading inobounce.js will define the iNoBounce namespace. If the loading environment supports AMD, iNoBounce will register itself as a model and forgo defining the namespace.

  • iNoBounce.enable()
    Enable iNoBounce. It's enabled by default on platforms that support -webkit-overflow-scrolling, so you only need to call this method if you explicitly disable it or want to enable it on a platform that doesn't support -webkit-overflow-scrolling.

  • iNoBounce.disable()
    Disable iNoBounce.

  • iNoBounce.isEnabled()
    Returns a boolean indicating if iNoBounce is enabled.

  • iNoBounce.isScrollSupported
    A boolean value that indicates if the -webkit-overflow-scrolling css property is valid, effectively a browser detection flag.

Will it break my app that uses touch events like other solutions?

It shouldn't. iNoBounce includes an example of a canvas drawing app and has been used in conjunction with Hammer.js without affecting functionality.

How does it work?

iNoBounce detects if the browser supports -webkit-overflow-scrolling by checking for the property on a fresh CSSStyleDeclaration. If it does, iNoBounce will listen to touchmove and selectively preventDefault() on move events that don't occur on a child of an element with -webkit-overflow-scrolling: touch set. In addition, iNoBounce will preventDefault() when the user is attemping to scroll past the bounds of a scrollable element, preventing rubberbanding on the element itself (an unavoidable caveat).

Shoutouts

How can I get that awesome iOS CSS skin from the app example?

Check out iOCSS for a lightweight and easy to use iOS skin for your mobile webapp.

Tapping stuff has a delay, what the heck?

You need FastClick by FT Labs.

Now I want awesome multi-touch gestures too!

It's hammer time, baby. Check out Hammer.js from Eight Media.

License

iNoBounce is licensed under the permissive BSD license.

inobounce's People

Contributors

95b avatar asos-dominicjomaa avatar benface avatar davidpett avatar jasonkuhrt avatar lazd avatar stity avatar webpro avatar wolthers avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

inobounce's Issues

Scroll disabled in Ipad Pro IOs 13

Hello! There is a problem on the iPad PRO IOs 13
Scroll simply does not work, in all other devices everything is fine, even in the same version of Safari.
Are there any solutions to the problem?

UPD: The problem is only in the vertical version, in the horizontal everything works

Error on iOS 11.0.3 Safari

The error:

Error: TypeError: Argument 1 ('element') to Window.getComputedStyle must be an instance of Element in innobounce-0.1.5.js at line 18

The line affected https://github.com/lazd/iNoBounce/blob/master/inobounce.js#L18

Proposed solution:

			var style = false;

			if (el instanceof Element) {
				// Get some style properties
				style = window.getComputedStyle(el);
			}

			if (!style) {
				// If we've encountered an element we can't compute the style for, get out
				break;
			}

Breaks time scrubbing on video tag

Time scrubbing/seeking on the built in video controls will not get the touchmove event. Work around is to set the overflow scrolling CSS properties on the video tag's parent, but this still affects the performance of the scrubbing.

iNoBounce breaks horizontal scrolling

Hi, I have a DIV purposely set to scroll horizontally however with iNoBounce it breaks this feature.

You can see the CSS and HTML here.

<div class="scrolls">
                <img src="http://placehold.it/50x50" />
                <img src="http://placehold.it/50x50" />
                <img src="http://placehold.it/50x50" />
                <img src="http://placehold.it/50x50" />
                <img src="http://placehold.it/50x50" />
                <img src="http://placehold.it/50x50" />
                <img src="http://placehold.it/50x50" />
                <img src="http://placehold.it/50x50" />
                <img src="http://placehold.it/50x50" />
                <img src="http://placehold.it/50x50" />
                <img src="http://placehold.it/50x50" />
                <img src="http://placehold.it/50x50" />
                <img src="http://placehold.it/50x50" />
                <img src="http://placehold.it/50x50" />
                <img src="http://placehold.it/50x50" />
                <img src="http://placehold.it/50x50" />
                <img src="http://placehold.it/50x50" />
                <img src="http://placehold.it/50x50" />
                <img src="http://placehold.it/50x50" />
                <img src="http://placehold.it/50x50" />
              </div>
.scrolls {
    overflow-x: scroll;
    overflow-y: hidden;
    height: 80px;
    white-space:nowrap
}
.imageDiv img {
    box-shadow: 1px 1px 10px #999;
    margin: 2px;
    max-height: 50px;
    cursor: pointer;
    display:inline-block;
    *display:inline;/* For IE7*/
    *zoom:1;/* For IE7*/
    vertical-align:top;
 }

Module support not working in Browserify

I'm loading iNoBounce as a module via Browserify and encountered a few issues. Both were related to global being undefined, one in the AMD global.define section, the other for the browser global. They were runtime errors which I fixed by updating the module detection code with boilerplate UMD:

(function(root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define([], factory);
    } else if (typeof module === 'object' && module.exports) {
        // Node. Does not work with strict CommonJS, but
        // only CommonJS-like environments that support module.exports,
        // like Node.
        module.exports = factory();
    } else {
        // Browser globals (root is window)
        root.iNoBounce = factory();
    }
}(this, function() {

    .... meat of code ...

    // A module to support enabling/disabling iNoBounce
    return {
        enable: enable,
        disable: disable,
        isEnabled: isEnabled
    };
}));

package support?

Are you open to a PR that would provide package support for component? Happy to oblige if so.

Enable zooming in iOS whilst keeping scrolling/bouncing disabled

0
down vote
favorite
I'm creating a web-app for iOS Safari and have run into a slight hurdle.

My web-app only takes up 1024x768 of screen real estate and therefore does not need scrolling, but it does need to be able to zoom (it's a PDF annotator).

I have used a plugin called iNoBounce (https://github.com/lazd/iNoBounce/) which successfully removes scrolling from the page by firing an evt.preventDefault() on the touchmove/touchstart events. This is great.

What this does though, is remove zoom events as well as scroll events. Is there a way to remove scrolling/elastic bouncing but to retain zoom on iOS safari?

Many thanks


I've managed to fix this issue, details here: http://stackoverflow.com/questions/37611300/ios-safari-disable-scroll-bounce-but-retain-zoom/37612533#37612533

Scrolling disabled on iOS

Hi, I've had a problem for a while now where when scrolling to the top limit of my website on an iOS device, it bounces back, I have a navbar that hides on scroll at the top, so when you scroll past the top boundary, the bouncing back makes the website think it's scrolling down, so the navbar hides. I tried to implement I no bounce, but it doesn't fix the problem, in fact it makes it worse, the user isn't able to scroll unless they zoom in or out, I was wondering if anyone could help me. This is the website: https://cloud.customquad.co.uk/my_sites/drones.html

JS error when scrolling outside <html>

If body and html don't have at least height 100% which is sometimes the case in apps that don't set html { height: 100% } body { min-height: 100% }, el.parentNode will be document and window.getComputedStyle(document) will throw an error. To fix this, I suggest changing line 16 from:

while (el !== document.body) {

to

while (el !== document.body && el !== document) {

Doesn't take into account all values for overflow

Hi - nice little library!

I was having a few issues, and realised that your library isn't taking into account all possible overflow/overflow-y values to determine whether a particular element scrolls. Adding the following fixes it:

var overflowY = style.getPropertyValue('overflowY');
// Determine if the element should scroll
var isScrollable = scrolling === 'touch' && (overflow === 'auto' || overflow === 'scroll' || overflowY === 'auto' || overflowY === 'scroll');

Thanks!

Hopeless battle with symptoms? Time to deal with the cause?

I found my way here after searching for a solution to the endlessly infuriating rubber-band-bounce issue on iOS. This project seems like the best solution to the problem on the internet. A lot of ingenuity, thought and effort has gone into it. And so it seemed like a good place to discuss this idea.

The problem here is that the damn rubber-band-bounce issue seems to keep coming back with each successive version of iOS - like some un-killable zombie creature... And the reason it keeps coming back to life is that this is a feature that Apple is deliberately adding because they think it is a good thing.

It seems to me, therefore, that the best solution would be to raise the issue with Apple and suggest that they provide a way of turning this feature off for people who don't want it. I think that there would be a lot of demand for such a switch and (given that the future of apps seems to be PWAs) this demand seems likely to grow.

Thoughts?

add "addeventlistener" to document instead of window?

Hello,

I use this script in connection with vuejs/vuetify/threejs. And for some reason your script does not work anymore after changing the route with the vuejs router.

I had to change "window" to "document" in your script to make it working.
these lines!

I am not a javascript expert, but you might have an idea why I had to do that. Is it possible to add this changes to your repo here at github?

Thank you for sharing this script. It saves me a lot of time to fix the shit apple had done (well, and took some time to find the solution for my problem :-).)

An error in [isAtBottom]

var isAtBottom = (startY >= curY && el.scrollHeight - el.scrollTop === height);
In this code, in some case, el.scrollHeight - el.scrollTop !== height, such as 900 - 450 !== 449.
So the height should be var height = Math.round(parseFloat(style.getPropertyValue('height')));

Breaks scrolling on iOS

In your example on iOS 14.2.1, the page cannot scroll whatsoever. However, when you click "disable" the page can scroll once more.

iOS 11.3: iNoBounce No Longer Works

  1. Specific steps you took to reproduce the problem

Steps:

  • Go to http://blog.lazd.net/iNoBounce (the demo page) on iOS 11.3 (beta)
  • Swipe up and down on the page, especially on static elements like the navbar,
  • The entire page is swiped just as if iNoBounce was not there.

Expected:

  • It should not scroll, but it does.
  1. The behavior you observed (do not simply write "not working")

Observed:

  • Swiping on stationary elements (such as navbars) on iOS 11.3 always will move the entire page.
  • Swiping up towards the top of a scrollable div will move the entire page.

Device:

  • iPhone 7, iOS 11.3
  1. Additional information
  • It works on the demo page and all examples of it, as well as Framework7-powered applications with iNoBounce implemented (which works on other iOS versions).
  1. Any workarounds you found
  • No workarounds have been found.

doesn't work anymore with ios9

Your demo only works if there is no momentum with existing scrolling.

Once there is scroll in motion, if you keep trying to scroll, the screen will bounce.

Window.getComputedStyle must be an instance of Element on iOS 11.3

I am getting the following error with our application when running iOS 11.3;

getComputedStyle@[native code]
r@https://localhost:8000/app.js:26:109    

message: Argument 1 ('element') to Window.getComputedStyle must be an instance of Element

Is there a fix for this? We are running iNoBounce version 0.1.6

Doesn't work in iOS 11.3.1?

none of the demos seem to prevent scrolling in Safari on iOS 11.3.1

In particular for me the Touchscreen Drawing Example scrolls while drawing. I'm guessing this is a bug in Safari? Not sure though

Example not working

Hi, the example list doesn't scroll. I'm running iOS 14.2. Any plans to make it compatible or am I missing something?

input type="range" preventDefault

if you got an input type="range" with no scrolling parent at all, we are gonna do preventDefault for every touchmove over this element .. then the slider never move

Does not work on bootstrap themes

I'm trying to disable bounce using bootstrap and a bootstrap theme but everything stop scrolling not just the bounce.

What's wrong?

Not always working on Iphone iOS 12 Safari after orientation change

After orientation Change ('resize' listener) I call in this order:

  • iNoBounce.disable();
  • window.location.reload();
  • iNoBounce.enable();

Sometimes there's no bounce, sometimes there is (only in landscape, in portrait is perfect).
Am I doing omething wrong? Any suggestion?

Thanks

Scrolling does not work in iOS 8.4

Hi!

I added your library to my single page app and it did prevent those bounces. But it also disabled absolutely all scrolling inside of the app. I use flex box layout.

I was able to reproduce it. Blue boxes will not scroll in Safari on iOS 8.4. Your library is added inline in the end. Without it it would scroll properly (and also would bounce as expected).

<!DOCTYPE html>
<html lang="en">
<head>

    <meta charset="utf-8"/>

    <title>Title</title>
    <style>

        .flex-box {

            display: flex; display: -webkit-flex;
            width: 100%;
            margin: 0;
            height: 300px;
        }

        .flex-box .col
        {
            border: 1px solid green;
            flex: 0.33; -webkit-flex:0.33;
            padding: 12px;
            overflow-y: auto;
            overflow-x: hide;
        }

        .handle {
            width: 5px;
            text-align: center;
            color: white;

            transition: all ease-in 0.1s;
        }

        .draggable { background: pink; }

        body {

        }


        .fxb {
            position: absolute;
            display: flex; display: -webkit-flex;
            flex-direction: column; -webkit-flex-direction: column;
            left:0;
            right:0;
            top:0;
            bottom:0;


        }

        .fxb-header {
            flex: 0; -webkit-flex:0;
            background: red;
            min-height:30px;
        }

        .fxb-body {

            flex: 1; -webkit-flex: 1;
            display: flex; display: -webkit-flex;
            background: blue;
        }

        .fxb-menu {
            min-width:300px;
            background: gray;
        }
        .fxb-handle {
            width: 5px;
            text-align: center;
            background: orange;

            transition: all ease-in 0.1s;
        }

        .fxb-content {
            flex: 1; -webkit-flex:1;
            background: white;
            overflow-y: auto;
        }

        .fxb-footer {
            flex: 0; -webkit-flex: 0;
            background: purple;
            min-height:30px;
        }

        .block {
            width: 150px;
            height: 140px;
            background: blue;
            margin-bottom: 10px;
            color:white;
        }

    </style>
</head>

<body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>

<div class="fxb">
    <div class="fxb-header"></div>
    <div class="fxb-body">
        <div class="fxb-menu"></div>
        <div class="fxb-handle"></div>
        <div class="fxb-content"><div class="block">as</div><div class="block">as</div><div class="block">as</div><div class="block">as</div><div class="block">as</div><div class="block">as</div><div class="block">as</div><div class="block">as</div><div class="block">as</div><div class="block">as</div><div class="block">as</div><div class="block">as</div><div class="block">as</div><div class="block">as</div><div class="block">as</div></div>
    </div>
    <div class="fxb-footer"></div>
</div>


<script>
    (function(global){var startY=0;var enabled=false;var handleTouchmove=function(evt){var el=evt.target;while(el!==document.body){var style=window.getComputedStyle(el);if(!style){break}var scrolling=style.getPropertyValue("-webkit-overflow-scrolling");var overflowY=style.getPropertyValue("overflow-y");var height=parseInt(style.getPropertyValue("height"),10);var isScrollable=scrolling==="touch"&&(overflowY==="auto"||overflowY==="scroll");var canScroll=el.scrollHeight>el.offsetHeight;if(isScrollable&&canScroll){var curY=evt.touches?evt.touches[0].screenY:evt.screenY;var isAtTop=startY<=curY&&el.scrollTop===0;var isAtBottom=startY>=curY&&el.scrollHeight-el.scrollTop===height;if(isAtTop||isAtBottom){evt.preventDefault()}return}el=el.parentNode}evt.preventDefault()};var handleTouchstart=function(evt){startY=evt.touches?evt.touches[0].screenY:evt.screenY};var enable=function(){window.addEventListener("touchstart",handleTouchstart,false);window.addEventListener("touchmove",handleTouchmove,false);enabled=true};var disable=function(){window.removeEventListener("touchstart",handleTouchstart,false);window.removeEventListener("touchmove",handleTouchmove,false);enabled=false};var isEnabled=function(){return enabled};var testDiv=document.createElement("div");document.documentElement.appendChild(testDiv);testDiv.style.WebkitOverflowScrolling="touch";var scrollSupport="getComputedStyle"in window&&window.getComputedStyle(testDiv)["-webkit-overflow-scrolling"]==="touch";document.documentElement.removeChild(testDiv);if(scrollSupport){enable()}var iNoBounce={enable:enable,disable:disable,isEnabled:isEnabled};if(typeof module!=="undefined"&&module.exports){module.exports=iNoBounce}if(typeof global.define==="function"){(function(define){define(function(){return iNoBounce})})(global.define)}else{global.iNoBounce=iNoBounce}})(this);


</script>

</body>
</html>

does this work for overflow-y

looking at the code I do not see how iy can work if you only have overflow auto in one direction... Would you like me to submit a patch?

Not compatible with svg inside "object" tag

Hello,

I'm developing a Framework7 app.
I use iNoBounce which works extremely well to disable the bounce except in one specific case.

I have a page that display an svg image.
If the image is directly inline in the page, or with an img tag, there is no issue.
BUT if I include the svg using an object tag (or using a embed tag, which is deprecated), then if i move the finger on the svg, it makes the app behave like there is not iNoBounce.

Do you have any idea how to correct this problem?

Thanks!

Not Working on Android Native Browser

Hey lazd, I am a UX Designer for a software company and I am using your plugin to disable the bounce in iOS (works perfectly in iOS), but unfortunately, it appears this breaks scrolling on elements using overflow in Android's native browser. Any ideas? Have you ran into this? Should this even be happening?

thank you

i download this js file and use it in my project, it's works,very userful ,thank you very much!

iPad Pro + Apple Pencil

With inobounce i have to tab multiple times (fast) with the Apple Pencil on clickable elements (button/anchor and other containers with onclick functions) to trigger an action.

if i remove the final evt.preventDefault() (after the while loop) it works fine.

iNoBounce kills native scrolling in Android 4.1.2 stock browser (Galaxy S2)

The (Samsung-supplied?) stock browser with the 4.1.2 version of Android has a strange quirk in that it reports that it supports webkit-overflow-scrolling.

!!('WebkitOverflowScrolling' in document.documentElement.style)

and

window.getComputedStyle(document.createElement('div'))['-webkit-overflow-scrolling'];

evaluate to true, which means that iNoBounce is enabled.
However, once the user attempts to scroll, in handleTouchmove()

var scrolling = style.getPropertyValue('-webkit-overflow-scrolling');

always returns an empty string (rather than 'auto' or 'touch'), so the action ends up being prevented and the page is stuck without a possibility to scroll.

The best fix would be to prevent iNoBounce from being loaded in the first place, but the only solution I can think of at the moment is using UA string detection.
Another way would be to reformulate the isScrollable condition from scrolling === 'touch' to the inverse scrolling !== 'auto':

var isScrollable = scrolling !== 'auto' && overflow === 'auto';

As of 7/2014, the Android 4.1.2 stock browser ranks #5 on our high traffic mobile website, behind only 2 versions of Safari and 2 versions of Chrome, so we have to find a workaround to prevent this iNoBounce issue.

This is the User Agent string of the affected browser: Mozilla/5.0 (Linux; U; Android 4.1.2; en-au; GT-I9100 Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30

Note: this bug is NOT present in the stock browser on an even older version of Android, 4.0.3, on a Galaxy S3.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.