Skip to content

Instantly share code, notes, and snippets.

@julienetie
Last active August 29, 2015 14:25
Show Gist options
  • Save julienetie/86ac394ec41f1271ff0a to your computer and use it in GitHub Desktop.
Save julienetie/86ac394ec41f1271ff0a to your computer and use it in GitHub Desktop.
Cleanly detect requestAnimationFrame iOS 6 bug without the use of user-agent sniffing.
/**
* hasIOS6RequestAnimationFrameBug.
* @See {@Link https://gist.github.com/julienetie/86ac394ec41f1271ff0a} - Commentary.
* @Copyright 2015 - Julien Etienne.
* @License: MIT.
*/
function hasIOS6RequestAnimationFrameBug() {
var hasMobileDeviceWidth = screen.width <= 768 ? true : false,
requiresWebkitRequestAnimationFrame = !((window.webkitRequestAnimationFrame && window.requestAnimationFrame)),
hasNoNavigationTiming = window.performance ? false : true;
if (requiresWebkitRequestAnimationFrame && hasMobileDeviceWidth && hasNoNavigationTiming) {
if (window.webkitRequestAnimationFrame || window.requestAnimationFrame) {
console.warn('This device may contain the iOS v6x webkitRequestAnimationFrame timing bug. For timing, please use an alternative such as the "setTimeout()" or "setInterval()" API');
return true;
} else {
console.info('hasIOS6RequestAnimationFrameBug is not applicable for this device');
return false;
}
} else {
return false;
}
}
@julienetie
Copy link
Author

A clean solution for the iOS 6 timing bug (2015)
Tested on all major mobile and desktop browsers.

Below is a quick copy and paste demo. Here's a fiddle: http://jsfiddle.net/julienetienne/je1kt6L2/8/

/**
 * requestAnimationFrameIOS6BugChecker.
 * @Copyright 2015 - Julien Etienne. 
 * @License: MIT
 */

// Is this "device|CSS width" mobile? http://mydevice.io/devices/
var hasMobileDeviceWidth = screen.width <= 768 ? true : false,

/** 
 * Does the browser "require" the prefixed version: "webkitRequestAnimationFrame"? 
 * IOS 6x uses Safari 6x (8536.25), therefore being the only iOS
 * version to require the webkit prefix.
 */
requiresWebkitRequestAnimationFrame = !( (window.webkitRequestAnimationFrame && window.requestAnimationFrame)),

/**
 * The problem with just the above is that we end up targeting all
 * mobile webkit devices that rquire the prefix. We solve this by
 * checking if the browser doesn't feature the "Navigation Timing API".
 * (All Android Chrome versions feature this API), and Android browsers 
 * prior to this feature support do not support requestAnimationFrame.
 */
hasNoNavigationTiming = window.performance ? false : true;

// Let's put it to use:
var rAFiOSBugCheck;
if (requiresWebkitRequestAnimationFrame & hasMobileDeviceWidth & hasNoNavigationTiming) {
    /**
     * We now feature detect to eliminate "iOS Safari & Chrome" versions 
     * that do not support requestAnimationFrame.
     */
    if(window.webkitRequestAnimationFrame || window.requestAnimationFrame){
    rAFiOSBugCheck = 'WARNING, this device has the iOS6' + rAF + 'bug';
    }else{
        rAFiOSBugCheck = 'requestAnimationFrame is not supported';
    }
} else {
    rAFiOSBugCheck = 'This device is clean';
}

// =====================================
// Display results.
var div = document.getElementById('results'); // For display.
var uaDiv = document.getElementById('ua'); // For display.
var rAF = requiresWebkitRequestAnimationFrame ? 'webkitRequestAnimationFrame' : 'requestAnimationFrame';
div.innerHTML = 'Screen width: ' + screen.width + '<br>' + 'Timing name: ' + rAF + '<h1>' + rAFiOSBugCheck + '</h1>';
div.style.fontSize = '1em';

// =====================================
// Display the iOS version using: ios-version.js https://gist.github.com/Craga89/2829457
var iOS = parseFloat(
    ('' + (/CPU.*OS ([0-9_]{1,5})|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent) || [0,''])[1])
    .replace('undefined', '3_2').replace('_', '.').replace('_', '')
) || 'Not iOS or cannot detect version';
// iOS version.
uaDiv.innerHTML = iOS;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment