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:

function addListener (element, type, callback) { if (element.addEventListener) { element.addEventListener(type, callback, false); } else if (element.attachEvent) { element.attachEvent("on" + type, callback); } }

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:

While Chrome’s support looks like that:

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:

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.