Before voting for duplicate:
Please read the full question below. I explained there why any of "how to detect mobile device?" is not a case here.
Question (and why it's not a simple negation of mobile dev. detection):
There are plenty of questions about "How to detect an mobile device with JavaScript?" (one of the best, if you are looking for it: What is the best way to detect a mobile device in jQuery?), but I want to ask for something a bit different: "How to detect non-mobile device with JavaScript?".
You might think that when I can make an mobile detection like this:
if(/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile
|Opera Mini/i.test(navigator.userAgent)){
alert('mobile');
}
I can just put negation before the statement inside if and that would be check for non-mobile device. Not really.
The code above detects several versions of mobile devices. For all not recognized devices, we cannot be 100% sure that they are not mobile. If userAgent contains one of the typed literals (webOS, iPone etc.) it's surely a mobile device. If not, it can goes two ways:
It's not a mobile device
It's a mobile device that we did not listed (mistake, exotic device, device released after we wrote the code etc.)
So instead of negating the test for mobile device, I want to write a test for non-mobile (Linux/Windows PC, Mac etc.). That way, if the result will be true, I will be 100% sure that I deal with non-mobile device. In the other case - it's rather mobile, but it's only an strong assumption.
So basically, I want to react only when I'm 100% sure it's non-mobile device, and when I do not know it for sure, I don't want to take any steps (or I will assume it's a mobile device).
How would that formula look? It's safe to test against Windows (Windows Phone or something like that could also use that literal?)? What about Mac, Linux PC and others?
This is taken from here:
var BrowserDetect = function() {
var nav = window.navigator,
ua = window.navigator.userAgent.toLowerCase();
// detect browsers (only the ones that have some kind of quirk we need to work around)
if (ua.match(/ipad/i) !== null)
return "iPod";
if (ua.match(/iphone/i) !== null)
return "iPhone";
if (ua.match(/android/i) !== null)
return "Android";
if ((nav.appName.toLowerCase().indexOf("microsoft") != -1 || nav.appName.toLowerCase().match(/trident/gi) !== null))
return "IE";
if (ua.match(/chrome/gi) !== null)
return "Chrome";
if (ua.match(/firefox/gi) !== null)
return "Firefox";
if (ua.match(/webkit/gi) !== null)
return "Webkit";
if (ua.match(/gecko/gi) !== null)
return "Gecko";
if (ua.match(/opera/gi) !== null)
return "Opera";
//If any case miss we will return null
return null;
};
It's not very elegant but you can add/remove it to your preference.
A second answer, while I understand you are specifically looking for a NON mobile detection, you could also use http://detectmobilebrowsers.com/ which has almost complete mobile device detection (Even the less popular).
Related
I can detect iOS 13 on iPhone but in iPad OS 13 navigator.platform comes as MacIntel. So it is not possible to get iPad identified using below code, but it works perfectly on iPhone.
if (/iP(hone|od|ad)/.test(navigator.platform)) {
var v = (navigator.appVersion).match(/OS (\d+)_(\d+)_?(\d+)?/);
var version = [parseInt(v[1], 10), parseInt(v[2], 10), parseInt(v[3] || 0, 10)];
return version;
}
When we request for mobile website using the browser on iPad navigator.platform returns as iPad and works perfectly.
Can anyone suggest a way to identify iPad running on iOS 13 and up using Javascript?
I was able to get iPad detection working by checking for navigator.maxTouchPoints as well as navigator.platform. It's not perfect (as discussed in the comments below) but it's the best solution I've come across so far so I wanted to share.
const iPad = (userAgent.match(/(iPad)/) /* iOS pre 13 */ ||
(navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1) /* iPad OS 13 */);
TL;DR
const iPad = !!(navigator.userAgent.match(/(iPad)/)
|| (navigator.platform === "MacIntel" && typeof navigator.standalone !== "undefined"))
We can use the navigator.standalone param. It's non-standard and used only on iOS Safari at present:
Navigator.standalone
Returns a boolean indicating whether the browser is running in standalone mode. Available on Apple's iOS Safari only.
When combined with navigator.platform === "MacIntel" iPad's are the only devices that define this property, therefore typeof navigator.standalone !== "undefined" filters out Macs running Safari (touchscreen or not).
I set up a CodeSandbox and manually tested on Browserstack, seems to work as expected: https://bc89h.csb.app/
Version Detection (iOS only)
I haven't tested this too extensively but should give anyone else looking a good place to start:
const version = navigator.userAgent.match(/Version\/(\d+)\.(\d+)\.?(\d+)?/);
const major = version && version[1] ? version[1] : "";
const minor = version && version[2] ? version[2] : "";
const patch = version && version[3] ? version[3] : "";
The above takes the version and breaks it down into major, minor and patch elements. This seems to work for iOS 12 & 13 which I ran a quick test against. The above SandBox link shows the output.
You can use WURFL.js, which is free if you just want to know what device is in use: https://web.wurfl.io/#wurfl-js
Full disclosure, I'm the COO of the company behind WURFL and ImageEngine, but I'm also an open-source developer :)
WURFL.js can tell you what OS is in use and if it's an iPhone or iPad.
To use it, just add this to the head of your page:
<script type="text/javascript" src="//wurfl.io/wurfl.js"></script>
Then you can use the device information in javascript:
console.log(WURFL.complete_device_name);
Note: With the paid version you can get more accurate results (ex: Apple iPhone XS Max, Apple iPad Pro 11) as well as a many other device characteristics.
If you don't need the device information for the initial paint, you can also run this asynchronously so it doesn't block rendering. Stick it at the end of the body and use async or defer:
<script type="text/javascript">
window.addEventListener('WurflJSDetectionComplete', () => {
console.log(`Device: ${WURFL.complete_device_name}`);
});
</script>
<script type="text/javascript" src="//wurfl.io/wurfl.js" async></script>
While you're at it, you might as well use this improved device information to enhance Google Analytics: https://www.scientiamobile.com/wurfljs-google-analytics-iphone/
Note that unlike the other answers, this one requires no ongoing maintenance on the part of the developer.
It's simple - you can't. You can only use hacks like this one
let isIOS = /iPad|iPhone|iPod/.test(navigator.platform)
|| (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)
The first condition for "mobile", second for iPad mimicking Macintosh Safari.
It works reliably for me, but who knows what will change in the future.
If there are to be macs with touch screen, this will detect not only iPads in Desktop mode, but also regular Macs.
The other way is feature detection - you can, but probably shouldn't rely on browser features support. For example, Safari on Mac doesn't support date picker, but the mobile one does.
Anyway, I suggest you try not to rely on platform detection (which will be broken in future anyway) and use feature detection (but not to distinct platforms) as Modernizr instead - if you want to use Date picker, you can check if it is available and if it's not, use an HTML solution instead. Don't lock out users just because they use some other browser. You may notify them but give them the option to hide the notification and use your site anyway.
As a user, I hate it when someone tells me to go and use another browser
Just remember - platform detection indicates a bad code smell since all these are hacks.
I did expand the implementation a little to make use of some more default browser features on iPad OS vs Mac OS Catalina.
According to my tests on diverse iPads and all late iOS Devices this works well.
var isIPadOs = window.AuthenticatorAssertionResponse === undefined
&& window.AuthenticatorAttestationResponse === undefined
&& window.AuthenticatorResponse === undefined
&& window.Credential === undefined
&& window.CredentialsContainer === undefined
&& window.DeviceMotionEvent !== undefined
&& window.DeviceOrientationEvent !== undefined
&& navigator.maxTouchPoints === 5
&& navigator.plugins.length === 0
&& navigator.platform !== "iPhone";
Gist: https://gist.github.com/braandl/f7965f62a5fecc379476d2c055838e36
It's a bit hackish and surely not very future safe but for now we are using the following and it seems to do the trick.
The first block is just sniffing the user agent for older iPads and the the second block after 'OR' is checking if the platform is Macintosh and has touch points. At the time of writing this, there's no official touch screen for Mac yet, so it should be pretty safe for a while.
if ((/\b(iPad)\b/.test(navigator.userAgent)
&& /WebKit/.test(navigator.userAgent)
&& !window.MSStream)
|| (navigator.platform === 'MacIntel'
&& navigator.maxTouchPoints
&& navigator.maxTouchPoints === 5)
) {
return true;
}
has anyone noticed that on the last version of Desktop Firefox, it is recognized as a touch device?
I am using the script below:
function isTouch() {
try{ document.createEvent("TouchEvent"); return true; }
catch(e){ return false;
}
}
if (isTouch()) {
alert('I am touch device!')
}
The script has given me flawless results up until the latest version of Desktop Firefox. Is it a bug? Am I missing something?
Thanks everyone for your time!
edit: False alarm people. I have no idea what went wrong, I tried resetting preferences, disabled all extensions but had no luck.
I finally solved the issue by REFRESHING firefox (lost all my extensions though and had to reinstall).
Thanks for everybody's efforts and sorry for any inconvenience caused.
You are just checking if you can create a specific type of event, not really if you are currently on a touch device.
Here is a more complete isTouchDevice function, which I wrote some time ago based on the core of Modernizr.
/**
* Detect if the current device is a touch device.
* Inspired by Modernizr and hardcore streamlined.
*/
function isTouchDevice() {
var bool;
if( ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch ) {
bool = true;
}
else {
var fakeBody = document.createElement( 'fakebody' );
fakeBody.innerHTML += '<style>#media (touch-enabled),(-webkit-touch-enabled),(-moz-touch-enabled),(-o-touch-enabled){#touchtest{top:42px;position:absolute}}</style>';
document.documentElement.appendChild( fakeBody );
var touchTestNode = document.createElement( 'div' );
touchTestNode.id = 'touchtest';
fakeBody.appendChild( touchTestNode );
bool = touchTestNode.offsetTop === 42;
}
return bool;
}
I've had a similar problem, and maybe some people will benefit from the information.
In my case, the Touch events were always detected as positive by Modernizr in Firefox desktop, even if they weren't fired.
In the end, I realized that 'dom.w3c_touch_events.enabled' had a value of '1' even if I didn't set it myself.
It was actually switched on by the "Touch" button in Responsive Design View, but never switched back to '0' even after disabling the Touch events with the very same button.
So I've reported a bug to Mozilla : https://bugzilla.mozilla.org/show_bug.cgi?id=1188270
You will find a test case there.
Basically, the only solution I had to go back to normal is to change manually the value of 'dom.w3c_touch_events.enabled' to '0' in 'about:config'.
And I'm now aware that by enabling Touch events in the Responsive Design View, I will have to manually switch it back after.
Hope this can help some people !
With navigator.vibrate one can make smartphones and tablets vibrate. However, the function is also available on desktop browsers, so its presence is not useful to detect whether a vibration motor is actually available.
Of course, I could check if the device is running a mobile OS for a decent approximation, but is there a proper way to detect whether vibration is actually available?
Reason: I'm using the vibration in a game, and include an on/off button for it. It makes no sense to show this button on a desktop PC.
Unfortunately, it sounds like you can't:
So apparently this is intentional, to avoid exposing accessibility
settings (which are seen as sensitive), to allow UAs to offer a
fallback, and potentially as a barrier to fingerprinting too.
From http://github.com/Modernizr/Modernizr/issues/1217
The spec itself says:
If pattern is an empty list, or if the device is unable to vibrate,
then return true and terminate these steps.
It seems impossible to detect if the device would actually vibrate somehow, so when I came to a similar problem I just used a fallback to sound if the OS seems not to be mobile device:
var navigatorTest = (function(ua){
return function(){
for(var i=0; i<arguments.length; ++i) {
if(ua.indexOf(arguments[i]) >= 0)
return true;
}
return false;
};
})(navigator.userAgent);
var bleep = ((
(navigatorTest("iPad", "iPod", "iPhone", "Android") || !navigatorTest("Macintosh", "Windows", "X11", "Linux"))
&& (navigator.vibrate || navigator.webkitVibrate || navigator.mozVibrate || navigator.msVibrate)
) || (
function(ctx){
return function(len){
var osc = ctx.createOscillator();
osc.connect(ctx.destination);
osc.start();
setTimeout(function(){
osc.stop();
}, len);
};
}
)(
window.AudioContext ? new AudioContext() : new webkitAudioContext()
)).bind(navigator, 300); // Vibration/bleep time
Although it is not what you mean (not a feature detection) it gives a fair fallback.
I need to check whether Flash player is installed and enabled or not in IE/Chrome.
((typeof navigator.plugins != 'undefined' && typeof navigator.plugins['Shockwave Flash'] == 'object') || (window.ActiveXObject && (new ActiveXObject('ShockwaveFlash.ShockwaveFlash')) != false));
and
!!(navigator.mimeTypes["application/x-shockwave-flash"] || window.ActiveXObject && new ActiveXObject('ShockwaveFlash.ShockwaveFlash'));
Both are fine for all the browsers in all OS except Chrome.For chrome it gives true even if I disable the Flash Player. But for IE it is behaving differently on different systems also not working in IE6 at all. How to check for IE/Chrome if flash is installed and enabled or not.
Too tired to write up a whole thing, so here is a fiddle with some flash/silverlight detection i wrote a while back. Feel free to play with it and remove the silverlight part if you don't need it.
It basically boils down to looping through all plug ins like this:
function get (name) {
for (var i = 0, l = navigator.plugins.length; i < l; i++)
{
if (navigator.plugins[i].name === name) {
return navigator.plugins[i];
}
}
return undefined;
}
http://jsfiddle.net/nQ7fk/
I guess you might have already ruled this out but I would recommend using swfobject to manage your flash insertion:
http://code.google.com/p/swfobject/
It does have features that let you detect if flash is installed and it also can trigger the installation process and manage your general flash insertion in a cross-browser, standards compliant way.
A client recently asked me to implement a slideshow on our website. I'm concerned that constantly animating picture transitions on the homepage will peg the processor of most mobile devices, so I want to disable the automatic advancing to preserve battery life. Is there any way to do this without trying to detect the user agent?
I've seen that there is a battery status API drafted here, but I don't know how complete it is, or which browsers have implemented it.
Actually determining battery would be quite difficult and probably involve various permissions problems.
Try just executing a small piece of code and checking the time it took. Pick a cutoff and if the code executes too slowly, turn off the transitions/animation/autoadvance. This will catch more than just battery devices; anything too slow will get the un-animated version. Degrade gracefully.
Now you can, with this API: http://davidwalsh.name/javascript-battery-api
navigator.getBattery().then(function(result) {});
Another old topic, but still relevant - I now check if the device has motion sensors, not many laptops do, but all modern smart phones and tablets do - so laptop users can live with slightly more battery use -
jQuery:
if (window.DeviceOrientationEvent) {
$(window).one("devicemotion", function(event) {
if (event.originalEvent.acceleration
&& event.originalEvent.acceleration.x !== null) { // Chrome fakes it on desktop
isMobile = true;
}
});
}
Plain Javascript:
if (window.DeviceOrientationEvent) {
window.ondevicemotion = function(event) {
if (event.acceleration
&& event.acceleration.x !== null) { // Chrome fakes it on desktop
window.ondevicemotion = null;
isMobile = true;
}
};
}