Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to automatically detect the need for iScroll?

The iScroll project provides the “overflow:scroll for mobile WebKit”, and was started

[…] because webkit for iPhone does not provide a native way to scroll content inside a fixed size (width/height) div. So basically it was impossible to have a fixed header/footer and a scrolling central area.

We have developed a mobile-friendly Web application, using responsive design (etc.), that uses a layout that sometimes show a fixed header and footer on mobile devices, based on the core-layout library, which in turn uses angular-iscroll.

You can try out the core-layout demo on desktop and mobile, and try to turn the use of iScroll on and off. On desktop scrolling the different areas should work both with and without iScroll (given that the window is not too high so that scrolling is not necessary); on mobile, however, whether scrolling works without iScroll depends on the kind and version of the browser.

Recent versions of the mobile Safari browser, and Android browsers, have started to support overflow:scroll for such fixed-size div elements as described above. Therefore, some browsers still need the use of iScroll to work, while other browsers don't. Because using iScroll introduces some problems on it own, like proper click and touch event handling, I would like to turn off iScroll in all browsers that don't need it.

I would like to add support in angular-iscroll or core-layout for automatically detecting if there is any need to use iScroll or not for each browser opening the page. I know about feature detection libraries like modernizr, but it seems hard to determine the need for iScroll based on feature detection.

Does anyone know how such auto-detection can be implemented?

Another possibility is to use a white/black-list and check the browser version, but in that case I wonder if anyone has a reliable rule set for properly determining the need to use iScroll based on the user-agent string?

Disclosure: I'm the author of both angular-iscroll and core-layout.

Update 2016-01-10:

Since no one have suggested any answers yet, I thought that I could share some ideas I've had of how to solve this:

  • If it is difficult to implement a solution to the above problem through true feature detection, one possible way could be to utilize platform.js, a platform detection library that works on nearly all JavaScript platforms. By including the platform.js script, you easily get access to information about the current browser such as

    // On an iPad
    platform.name; // 'Safari'
    platform.version; // '5.1'
    platform.product; // 'iPad'
    platform.manufacturer; // 'Apple'
    platform.layout; // 'WebKit'
    platform.os; // 'iOS 5.0'
    platform.description; // 'Safari 5.1 on Apple iPad (iOS 5.0)'
    

    which could be used for matching against a rule set. However, then the
    problem becomes what those rules should be, to avoid turning off iScroll for browsers that need iScroll to work, and to avoid turning iScroll on for browsers that don't need it.

  • Another way might be to exploit that, given a scrollable div with higher contents that the div's height, then the scroll area should scroll when swiped, and one could try to detect whether or not that happens.
    Consider this scenario: let's assume that you start of with iScroll turned off. Now, if the user tries to scroll the contents of the div, but the contents don't move, then perhaps one could conclude that one must turn iScroll on for div-scrolling to work? How would that be implemented while providing a relatively smooth user experience? It might depend on how fast one can detect that the contents should have scrolled but didn't?

If anyone can come up with robust solutions based on one of those ideas (or a combination of them), then I'm just happy to help.

Also, I wonder why no one tries to come up with an answer; not even a comment that says this is too difficult/trivial/irrelevant/strange/outdated?

like image 907
Martin Thorsen Ranang Avatar asked Jan 07 '16 10:01

Martin Thorsen Ranang


1 Answers

Since no one else have come up with a solution yet, I thought I could share mine, and hopefully, this answer can be edited and improved to more precisely decide for which devices iScroll must be used.

I wrote the following Modernizr extension that makes use of platform.js to decide if native overflow: scroll div scrolling is supported:

'use strict';

var platform = require('platform'),
    Modernizr = require('modernizr');

function _isChromeMobile(platform) {
    return platform.name === 'Chrome Mobile';
}

function _isAndroidBrowserWithRecentOS(platform) {
    return platform.name === 'Android Browser' &&
        versionCompare(platform.os.version, '4.0.4') >= 0;
}

module.exports = function _useNativeScroll(platform) {
    if (platform.name === 'Opera Mini') {
        return false;
    }

    if (platform.name === 'IE Mobile') {
        return versionCompare(platform.version, '11.0') >= 0
    }

    switch (platform.os.family) {
        case 'Android':
            // In Chrome we trust.
            return _isChromeMobile(platform) ||
                _isAndroidBrowserWithRecentOS(platform);
        case 'iOS':
            // Buggy handling in older iOS versions.
            return versionCompare(platform.version, '5.1') >= 0;
        default:
            // Assuming desktop or other browser.
            return true;
    }
};

Modernizr.addTest('usenativescroll',
                  require('modernizr-usenativescroll'));

Where compareVersion(), by Jon Papaioannou, is defined in How to compare software version number using js? (only number) or this gist with documentation.

Now, this method unfortunately does not use feature detection, but can hopefully be further improved if anyone comes up with more facts about problematic devices or browser versions.

Update 2016-01-27

Thanks to a generous “free for Open Source” sponsorship from BrowserStack, I've been able to test core-layout, and thereby angular-iscroll, with a plethora of devices and browsers. Based on those tests, I've refined both angular-iscroll's auto-detect rules, and the above code.

Update 2016-01-25

Since version 3.1.0 angular-iscroll has this feature builtin. The result of the automatic detection is exposed via the boolean flags iScrollService.state.autoDetectedUseNativeScroll and iScrollServiceProvider.useNativeScroll; where the latter is available during the config phase of the app initialization.

like image 68
Martin Thorsen Ranang Avatar answered Oct 13 '22 01:10

Martin Thorsen Ranang