11

I want a single site that uses the same HTML but "widgetizes" it in the best way for the platform it's served to.

Is there a standard practice for feature detecting mobile devices / hardware keyboards on the client and deciding whether to load jQuery Mobile along with the site's mobile JavaScript or jQuery UI and a script for a desktop experience?

The following seems like a reasonable way to do it but I wonder if Modernizr.touch is the best way to detect this? e.g.: Forcing touch might not be the best solution for Surface. Is there any way to detect if there's also a hardware keyboard?

Modernizr.load({
  test: Modernizr.touch,
  yep : ['jquery-mobile.js','mobile.js']
  nope: ['jquery-ui.js','desktop.js']
});

Edit:

Found some relevant Modernizr bugs:

I guess what I really need is a way to detect both whether the device is capable of touch and if it has a hardware keyboard. I could use David Mulder's answer for detecting device width in physical units (inches) as a proxy for that and assume anything > 11 inches has a keyboard, but I bet there's a massive tablet out there (or Google will release a nexus 12 tablet :) where that would make a wrong assumption.

Community
  • 1
  • 1
Sam Hasler
  • 12,344
  • 10
  • 72
  • 106
  • I don't know that much about Modernizr, but I think the standard way is checking the screen width for delivering special js and css for smaller devices. – Joshua Mar 06 '13 at 09:47
  • @Joshua, screen width might be unreliable though. If I wanted to expand this to have a tablet mode too then how would I tell the difference between a narrow window on a desktop and a tablet? It there's a media query that can reliably detect mobile/tablets I could use this: http://bricss.net/post/22198838298/easily-checking-in-javascript-if-a-css-media-query-has although I've found it a little slow, and it won't work on IE9 – Sam Hasler Mar 06 '13 at 15:12
  • 1
    There are so many mobile devices out there, and [even the most popular ones have highly variable screen widths](http://www.responsinator.com/). Detecting touch events is NOT the right way to handle things. Standard practice is to provide different responsive layouts depending on screen width. – Blazemonger Mar 06 '13 at 16:07
  • @Blazemonger, I know how to do RWD layout. I'm more interested in applying different jQuery (or vanilla JavaScript) components/widgets to an input if it's on mobile, tablet or desktop. One component might be better suited for entering dates on mobile using drop downs, a tablet one might show a calendar with larget touch targets, a desktop one might interpret text input like "tomorrow" or "next Wednesday" – Sam Hasler Mar 07 '13 at 01:18
  • If you really want to distinguish between browsers, you can only check the `navigator.userAgent`, although this is considered not that reliable. Google gave me these SO links: http://stackoverflow.com/questions/12342092/how-to-detect-touch-device-browsers-vs-desktop-using-javascript and http://stackoverflow.com/questions/14661876/distinguish-between-a-pc-or-a-smartphone-tablet-in-a-website. Maybe there you find something useful. It seems not to be trivial to find out if you are currently on a tablet, smartphone or desktop pc. – Joshua Mar 07 '13 at 08:32
  • Additionally this link seems to be quite worth readable too: http://x7.fi/2010/02/12/how-to-fit-your-website-for-the-apple-ipad/. It's about media queries and ipads. – Joshua Mar 07 '13 at 08:38
  • 1
    The problem is that there's no longer any clear way to distinguish between a smartphone, a tablet, and a desktop. MS Surface and Asus Transformer are both tablet and desktop; A Kindle or Galaxy note is somewhere between a smartphone and a tablet. There is NO meaningful way to distinguish between the three categories. You need to decide what it is you are REALLY trying to distinguish between and measure that instead. – Blazemonger Mar 07 '13 at 13:06
  • @Joshua, I want something that will still work with devices/browsers that come out in the future. User agent checking will only work with today's devices. I want a solution that works by feature detection so it will work with any device that supports the feature. – Sam Hasler Mar 07 '13 at 14:20
  • @Blazemonger I guess since the components I'm using will be aimed at either touch or keyboard input I want a solution that can detect one or both of them. So Modernizr.touch may be the best solution, although for devices that have touch and a keyboard that might result in a non-optimal interface selection. I guess what I really want is a way to detect presence of a hardware keyboard. – Sam Hasler Mar 07 '13 at 14:25
  • 1
    http://stackoverflow.com/questions/13270659/detect-virtual-keyboard-vs-hardware-keyboard – Blazemonger Mar 07 '13 at 14:45
  • Soo, if you can't make clear what you really want, it's quite hard to help you. I think, @Blazemonger's link will help you the most. I'm outta here. – Joshua Mar 07 '13 at 14:48
  • @Joshua I thought I had. I want to be able to detect: 1. Is it a touch device? 2. Does this device have a hardware keyboard? – Sam Hasler Mar 07 '13 at 15:05
  • @Blazemonger, good find with that question. Pity the best answer was "make a virtual keyboard optional" – Sam Hasler Mar 11 '13 at 13:49

4 Answers4

2

Ok, I don't have the devices at my disposal right now to check this, but the way to go is something along the following lines:

DPI can't be calculated straight from JS, but

var dpi = 50;
while(window.matchMedia("(min-resolution: "+dpi+"dpi)").matches && dpi<500){
  dpi+=1;
}

is possible which allows us next to calculate the screen diagonal like this

var screendiagonal = Math.round(Math.sqrt(Math.pow(window.screen.availHeight,2)+Math.pow(window.screen.availWidth,2))/dpi)

if (screendiagonal < 4) "phone"
else if (screendiagonal < 11) "tablet"
else "computer"

Let me again repeat that I have never done such a thing before and especially in that first piece of code there might be a mistake, however something like should be possible and I will check tonight if I don't forget.

Oh and it's good to note that this won't work on desktops, so an additional check should be made whether the final dpi is 500 in which case it's a desktop system (though the userAgent may examined too for this). Additionally it might be necessary to figure out the -webkit-min-device-pixel-ratio value as well to incorporate this in the calculation (just loop over it till you find the correct ratio and multiply the dpi by this ratio).

David Mulder
  • 26,123
  • 9
  • 51
  • 114
  • I so like your idea. That's awesome - too sad that one cannot really rely on your code. One could think, that HTML5, JS and CSS3, all this stuff, would finally deliver a way to solve this kind of problems. – Joshua Mar 07 '13 at 13:22
  • looks like it doesn't loop on desktop, so it stays at 50. Neat idea though! – Sam Hasler Mar 07 '13 at 14:18
  • As I said: "Oh and it's good to note that this won't work on desktops, so an additional check should be made whether the final dpi is 500 in which case it's a desktop system" – David Mulder Mar 07 '13 at 14:56
  • I've run it on chrome desktop and final dpi was 50, not 500. – Sam Hasler Mar 07 '13 at 15:07
  • *facepalm*, yeah, you're absolutely right, I misremembered and misread your comment... – David Mulder Mar 07 '13 at 15:14
  • 1
    I have just run some additional tests on a iOS device, it seems it might be necessary to dynamically insert a stylesheet and edit it's content rather than using the window.matchMedia function, however the technique outlined is functional (just have to add the updating and looping mechanism, which I will do and maybe release as a full fledged script). – David Mulder Mar 13 '13 at 09:26
0

If your not married to jQuery UI and jQuery Mobile then Twitter Bootstrap Fluid layout does a pretty good job w/o having to change HTML or CSS for different devices. You can easily see this by going to the Twitter Bootstrap site and re-sizing your browser to different sizes.

What your looking for in general is what is called responsive design. Its based on CSS media queries and a little Javascript usually to massage the crap that is IE < 9 to render correctly. The other reason I like bootstrap is that it has a giant community managing this "massaging" of new devices instead of you.

Adam Gent
  • 47,843
  • 23
  • 153
  • 203
  • I can do the layout part of RWD. My specific problem is that I want to use different UI widgets depending on whether the device is mobile/tablet/desktop. – Sam Hasler Mar 14 '13 at 11:57
  • Maybe I should delete my answer if its not helpful? If you play with bootstrap you can clearly see it re-renders widgets based on screensize (ie the facebook like menu button shows when a screen reaches a certain size). I wish someone would just write a comment before downvoting. I'm happy to delete the answer. – Adam Gent Mar 14 '13 at 18:34
0

You could try this php library

https://code.google.com/p/php-mobile-detect/

Or this one for javascript

https://github.com/hgoebl/mobile-detect.js

ejectamenta
  • 1,047
  • 17
  • 20
-4

Easiest way is to detect the user agents you want to target and load the appropriate javascript.

function load(src) {
  var doc = document,
    application = doc.createElement('script'),
    script = doc.getElementsByTagName('script')[0];
  application.type = 'text/javascript';
  application.async = true;
  application.src = src;
  script.parentNode.insertBefore(application, script);
}
load(/Android|webOS|iPhone|iPad|iPod|BlackBerry|Windows Phone|iemobile|tablet|Opera Mobi/i.test(navigator.userAgent) ? 'handheld.js' : 'desktop.js');

Better and more costly way is to let the backend deal with this using wurl for content negotiation to serve the proper (javascript) assets for desktop or handheld devices (check for is_wireless_device = true for handheld).

del
  • 11
  • 1
  • 1
    I want to use feature detection, not browser sniffing. I don't want to have to update this every time a new phone comes out. – Sam Hasler Mar 11 '13 at 13:48
  • What you're asking for might be device and not feature detection. If I have a desktop computer that is attached to a touch enabled screen at 2048x1536 and 264ppi, if you check for feature it will be indistinguishable from an retina ipad since both have the same features. That is why you need to check it against a device matrix and using wurfl, all the maintenance will be taken care of for you. – del Mar 11 '13 at 18:46
  • 1
    Browsers can lie in navigator.userAgent so it shouldn't be trusted, and if a device feature detects to be identical to an iPad then it should get the same site as an ipad. What's missing is being able to feature detect if the device has a hardware keyboard. That's what I'm asking for. I realise that this might not exist *yet* but I'm hoping that one day it will. – Sam Hasler Mar 12 '13 at 13:48