User-agent sniffing is back

Matthias Reuter's picture

HTML5 brought many good features, but it also brought back user-agent sniffing.

User-Agent sniffing is the nemesis of good modern web development, and that's for a good reason. As a person who uses Opera since version 4 as his main browser for surfing (not for development though) I have suffered through many bad scripts which try to exclude me just on the grounds I am using neither Internet Explorer nor Firefox. Or neither Internet Explorer nor Netscape. I have ranted against scripts that told me my browser was outdated and I should switch do a newer, faster and better browser like IE, even though I used the latest ubuntu version of Opera.

User-Agent sniffing dates back to when browser vendors extended their products with cool new features like the marquee element (I hope you noticed the sarcasm) and web developers had to find out, if they could use these. Often that led to two completely seperate versions of the web site and the user being redirected to one of them depending on his user-agent (or not being redirected at all, if the user-agent did neither match the sniffing for IE or Netscape).

Many web developers fought the fight to replace user-agent sniffing by feature testing. Instead of looking at the user-agent and thereby deriving from a name what the browser is capable of, it is definitevly better to look at what the browser says it is capable of. This is an example for a very common use case:

  1. function addListener (element, type, callback) {
  2.     if (element.addEventListener) {
  3.         element.addEventListener(type, callback, false);
  4.     }
  5.     else if (element.attachEvent) {
  6.         element.attachEvent("on" + type, callback);
  7.     }
  8. }

This script handles the different event models which exist in browsers, the standardized model of the W3C (addEventListener) and the proprietary model of Microsoft (attachEvent).

What is the advantage of feature detection? It does not break future versions of browsers. If a future version (like IE9) supports a certain feature (like the W3C event model, which by the way it does), we don't have to change our script, it continues to work. User-agent sniffing on the other hand, has to be adapted whenever a new browser or a new version of an existing browser is released, since that browser might support a feature a former version did not.

Now most will agree that feature detection is superior to user-agent sniffing. However, feature detection is not a replacement for user-agent sniffing, in fact, sometimes we have to use user-agent sniffing. We rarely need it, but the use of HTML5 increases the need of user-agent sniffing.

User-agent sniffing is necessary when a browser does support a certain feature but has a bug in it. I once had the case that a former version of Safari had a bug in its implementation of document.querySelectorAll, where in certain circumstances the returned NodeList contained null. While there is the theoretical possibility to feature-test bugs, this fails when the browser crashes when using a feature in a special way, as it happened to a friend of mine on a beta version of Safari. There is no way to feature detect a browser crash.

Bugs in implementations of features are quite rare, but what if a browser supports a feature, but not in a way you like? This is very common for features of HTML5.

HTML5 has several new type for the input element. A very convenient type is date. It is quite easy to do a feature test, if the browser supports that type:

function hasTypeSearch() {
    var input = document.createElement("input");
    input.setAttribute("type", "date");
   
    return input.type === "date";
}

This test works because browsers which do not support date will fall back to the type text. But this does not help at all. Opera's support for the date type looks like this:

Input element with type date in Opera, showing a datepicker

While Chrome's support looks like that:

Input element with type date in Chrome

Both browsers support the date type, but while Opera has a full featured date picker, Chrome only has two buttons to increase or decrease the date.

Now if you want to enhance browsers which do not have a datepicker natively - maybe by adding a jQuery UI datepicker - there is no way to feature detect that.

Similar, the search type is supported by many browsers. On Safari for Mac it looks like that:

Image

On all other browsers I tried it looks like an ordinary text field. This is due to the specification, which says:

On platforms where search fields are distinguished from regular text fields, the Search state might result in an appearance consistent with the platform's search fields rather than appearing like a regular text field.

Offering that little x to reset the search is a feature one would like in all browsers on all platforms, but again, there is no way to feature detect this.

HTML5 makes us need user-agent sniffing.

What can we do about this? Nothing. We could only keep user-agent sniffing to a minimum. That is, first try to feature detect. Only if that succeeds, do a user-agent sniffing.

function hasDatepicker () {
    var input = document.createElement("input");
    input.setAttribute("type", "date");
   
    if (input.type !== "date") {
        // does not support type date
        return false;
    }
   
    // currently only Opera supports date as we want it
    return navigator.userAgent.indexOf("Opera") !== -1;
}

This leaves us in the sorry state that we have to monitor browser development closely. Whenever a browser changes, we might need to adapt our sniffing. HTML5 brought many good features, but it also brought back user-agent sniffing.

Comments

Dean Edwards's picture

I'm trying to write a library to support HTML5 form controls and Google's partial implementation makes it impossible without browser sniffing.

Jarvklo's picture

FWIW and IMHO
Since browser sniffing usually includes sniffing for version as well as make/model of browser - this makes a strong case for why we permanently need browser versioning on the web from now on...

And ultimately we will need it also in HTML5 unless someone invents something better...

Eg. IMHO a modular approach with versioned modules (including test specs and independent compliance monitoring) together with a non-scriptdependent capability negotiation mechanism would be *way* better than the suggested non versioned approach for HTML5 that requires us to send out a lot of capability checking scripts to every visitor...

Ultimately and IMVHO we would benefit a lot more from some way of determining feature capability sever side in order to avoid sending out "polyfills" and workarounds to browsers who doesn't need them. If you host in the "cloud" e ery byte you can save is worth real money on a high volume site (not to mention speed if you can minimize http-requests by filtering out polyfill- and capability checking javascripts alreAdy on the server side)

Chris Heilmann's picture

The problem is not HTML5, the problem is browser support. In this case, Chrome rendering a date picker as a number field - that doesn't make any sense.

Sniffing Opera as the only browser here to have a date picker is not safe as the next version of Chrome might very well have a proper picker.

Matthias Reuter's picture

You're right, it's not HTML5 who is the villain. And with any type of user-agent sniffing we have to check if it's still correct for every new version of a browser.

Jarvklo's picture

I agree - HTML5 will be an excellent baseline once we have interop (and it already is in some respects) - I'm talking about the future and how I would wish we could detect new or altered features in the long run in a solid and verifiable way - and that browser sniffing proves that versioning works well ;)

E. Nuffall Reddy's picture

With Firefox, I can use User Agent Switcher to send special UA strings like "OHGODMYEYES!" or "Got Enough ADS, Whoreboy??". The enjoyment I derive from these is, admittedly, out of all proportion with their actual effect, but I just can't help myself.

Nicolas's picture

Well if you need to use you own datepicker control or search text control for some browsers, why not juste use them on ALL browsers ? There is no point to code things twice.

Personnaly, I think the date picker field for exemple is no a very valuable HTML5 feature as you can perfectly do without. And if you use it you might see that it's not really adapted to your domain need. Maybe you just want a month picker ? Or allow only for a subset of dates ? Maybe your users use public computer and and don't want that the date picker is localised toward browser locale instead of user account locale?

You should use the build in browser feature if it work for all browsers and fits all you needs. Go back to a unified custom solution otherwise.

Matthias Reuter's picture

HTML5 not only has the type date but also datetime, month, week, time and datetime-local, as well as the attributes min and max. That should allow for a broader range of use cases.

I still would like to fallback for a javascript datepicker only when neccessary. The reason is performance. The user would load the HTML5 page, and a small script would detect which features are supported. The fallback is then only loaded for those unsupported features. That would save bandwidth, which is quite important. Users of Opera Mobile for example would experience a much faster page load than users of webkit mobile.

Paul Irish's picture

The base feature test that you outlined (checking the type attribute) works well to filter out some, but you end up with false positives.

That sucks, but it happens a lot (in all browsers).

In the case of inputs, a more rigorous feature test (and the one we do in Modernizr) is to see if the value sanitization algorithm defined in the spec kicks into action. If it doesn't, it's a pretty good bet the new input type isn't done.

I actually confirmed this with Google's webforms engineer: he will not add any value sanitization to the inputs if the associated UI is not there yet. So, for webkit at least, we can rely on that being an feature inference of proper datepicker UI.

@Dean,

Take a look at the Modernizr source and you'll see this sort of thing documented quite well. So far, I've seen no evidence that UA parsing is required for webforms, unless you've decided that FF's search input is ugly and not searchy enough.

John-David Dalton's picture

Bugs in implementations of features are quite rare,

I disagree, there are a ton of bugs in features, like querySelectorAll, cloneNode, innerHTML, Array#concat, & so on.
I'm not surprised you had browser stability issues in beta release but I don't think it's a knock against feature testing.

I dig that you promote UA sniffing as a last resort and cover some alternatives to UA sniffing in a series of short screencasts.

If you want a truly consistent UI then you should simply use your JS widget lib of choice for all browsers. It would be less maintenance and headache (you could then focus on minification, caching, & reduced/slimmed UI builds).

Custom Website Development's picture

HTML5 has made good features compared to older version. But this is one among different problem which user of HTML5 has experienced till date. By making it minimum, user experience can be improved but hope it is not the solution. some new improvement is required.

Custom Website Development

Christian's picture

PPK has written about the bad mobile browser support, and the browser Obigo wins: http://www.quirksmode.org/blog/archives/2011/03/the_new_input_t.html

180+ HTML5 Tutorials and a Round-Up of Round-Ups - WebsitesM's picture

[...] User-agent sniffing is back (Matthias Reuter | Feb 15, 2011) [...]

270+ HTML5 Tutorials and a Round-Up of Round-Ups - WebsitesM's picture

[...] User-agent sniffing is back (Matthias Reuter | Feb 15, 2011) [...]

William Smith's picture

It's nice to look the web development rising to such a extent. In early days we just had an html view of a page from where we have to gather required information and then came the world of web 2.0, which has changed the entire way of communication through online mode. Face book and twitter are one of the best example of web 2.0 websites.