I am thrilled we've gotten to the point in the web where progressive enhancement is in vogue, finally falling in line with our own practices of the last decade or so. With the advent of mobile devices and plunging screen resolutions, we have support in the form of CSS media queries to adapt a single page to multiple devices, now referred to as responsive web design. Yes, we are still struggling with the best practices and design differences (such as forgetting print styles), but the overall concept is solid. No longer must you code a text-only page, a mobile page, a printable page, and a regular page (or the templates for each if you are using a web content management system). You can build one page and let it handle all those scenarios.
Except sometimes you find yourself in a situation where you have been asked to develop a different experience for a mobile user that lies outside the ideal of responsive sites. That different experience can be as simple as sending a user to a different page on the site if he or she is surfing on a mobile device. All those years of progress are swept away in one moment and we are back to struggling with user agents. I'd like to provide a little context on why such a simple-sounding request can be such an effort to implement.
If we fall back to user agent sniffing (reading the browser's User Agent as it reports to the server), then we have an uphill battle. Just finding a comprehensive list is an effort. One site lists hundreds of user agent strings, and there is even a SourceForge project dedicated to staying on top of them all. When you consider how many different phones and browsers there are, and how often new ones come out (such as Amazon Silk), your clients need to understand that this approach is doomed to failure without ongoing updates (and fees).
If all you do is follow Google's advice on its Webmaster Central Blog to simply look for the word "mobile" in the string, you'll fail immediately — user agents on Android devices do not need to conform (and often don't) to what Google says you will find. Opera doesn't include "mobile" in its user agent (
Opera/9.80 (Android 2.3.3; Linux; Opera Mobi/ADR-1109081720; U; en) Presto/2.8.149 Version/11.10), and the browser Dolphin doesn't even include its name in the user agent string (
Mozilla/5.0 (Linux; U; Android 2.3.3; en-us; PC36100 Build/GRI40) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 ).
You can take the inverse approach and instead detect for desktop browsers. It's smart and simple as far as user agent sniffing goes, but still falls prey to the same problem of the constantly changing landscape of browsers. Given that the next version of Windows is intended to quickly switch its interface back and forth between desktop and mobile (keyboard and touch), unless the user agent for all the browsers installed on that device change as the user changes the device orientation, that technique is also doomed.
Serving different content based on screen resolution gets you around the user agent sniffing, but isn't any more effective. With tablets approaching desktop screen resolution, and smartphone resolution approaching tablet resolution, there is no clear method for determining what kind of device a user has. An iPhone 4S held horizontally has 960 pixels of resolution and the Dell Streak tablet has 800 pixels (to clarify, the smaller device has more pixels, which is contrary to what most might expect). If you want a tablet to have a different experience than a phone, then serving it based on screen resolution won't do it. As it is, the resolution of many tablets matches that of my netbook (1,024 x 600), which is definitely not the same type of device (it has a keyboard, for example).
What To Do?
Try to solve the objective earlier in the overall process — generate a different URL for mobile, embed it in different QR codes, look into feature detection, look at using CSS media queries to display or hide alternate content, and so on. Every case may require a different solution, but falling back to methods that were never reliable certainly isn't the right default approach.
Update: November 13, 2013
I'm just going to leave this link here for you to read at your leisure: Internet Explorer 11’s Many User-Agent Strings