Browser detect 2.0

I'm in an ethical quandary. I've written a new browser detect script that's definitely better than the old one, but I hesitated for almost a day before publishing it. I'm afraid that amateur web developers will take the function and abuse it. Nonetheless, I decided to publish. I just hope I won't be sorry a year from now.

Here it is. It uses navigator.vendor wherever possible, because this property is much more reliable than the good old navigator.userAgent. I also ported the whole script to one neat object that can be dropped into any script.

Adding objects

The script works in all browsers I possess, but on Linux, especially, there are a few obscure browsers that I haven't installed and can't test. Besides, there's no detect for Unix as opposed to Linux. Fortunately this new script allows you to easily add little objects to perform a certain detect, and I hope my readers will submit such new objects in the comments below.

No "framework programmers", please

Browser detects are the most abused feature of JavaScript. Newbies, esepcially, tend to hugely overrate their power, and use them all the time—and I count Java- and other server side programmers who're switching to JavaScript to hitch a ride on the Ajax bandwagon as newbies, too.

The problem is that most people who use browser detects are amateurs who tend to divide the world into "Explorer" and "other" (some add a "Mozilla" category, but even that is rare) without the slightest browser knowledge. Their main reason for doing so is laziness: they refuse to take the time and trouble to understand browsers and object detection.

If I get any hint that someone with only a nodding acquaintance of JavaScript uses my script in his "Ajax framework" to make vital application logic decisions for him, I won't rest until I've made him ridiculous in the eyes of the world. If you think you need browser detects, you can be sure you don't know enough about browsers.

There are legitimate uses of browser detects (my current project has uncovered a few), but newbie JavaScripters are unable to properly define them. Therefore this script is only for experienced scripters who're used to herding browsers by hand and who have at least a few years of experience. Only they are able to distinguish between correct and incorrect uses of browser detects.

The danger of publishing browser detect scripts

Right now navigator.vendor contains reliable information about the browser, although some browsers (notably Explorer and Mozilla) don't support it. However, if all browser detect scripts were to start using navigator.vendor in order to exclude, say, Safari, Opera, and iCab from sites, the browser vendors will be forced to react.

Their reaction will be predictable: they'll make sure that navigator.vendor contains the value that these oh-so-clever detection scripts expect. Of course that effectively ends the property's usefulness: you'll never know if navigator.vendor's value is real or a spoof. See section 3D of the book for a full explanation of this mechanism.

The more this script is used, the less likely it is to stay current. In order to keep this script up-to-date you should use it as little as possible.

This is the blog of Peter-Paul Koch, web developer, consultant, and trainer. You can also follow him on Twitter or Mastodon.
Atom RSS

If you like this blog, why not donate a little bit of money to help me pay my bills?

Categories:

Comments

Comments are closed.

1 Posted by Small Paul on 25 July 2006 | Permalink

Yay! Finally, a good modern way to make sure people have to use Explorer to view my client's sites: it's so much easier that way. My new AJAX framework is gonna rool now, thanx.

Just kidding :)

2 Posted by Miroslav Dimitrov on 25 July 2006 | Permalink

One use of such script is for a page counter. Many such counters also detect various properties of the user agent such as its name, version, etc.

I definitely prefer this to be done server-side. I.e. the javascript only sends whatever information (not available in the HTTP headers) is necessary to the server where the parsing is done.

However there are some "counters" that do this on the client-side. In this case it must be ensured that the counter won't interfere with the user's experience, no matter what browser she is using. Which leads me to what I wanted to point out: that in this case only JavaScript 1.0 features must be used, i.e. no array and object literals.

On the other hand as you said, if this script is going to be used mainly by experienced javascript programers then they should know about this.

3 Posted by Simon C on 25 July 2006 | Permalink

The most recent time I was forced to use a browser detect was in a script I wrote for a drag & drop timesheet control. Even then I could have gotten away without using it; I only used it because of the two methods I wrote for a particular feature, one ran much quicker in Explorer, and the other much quicker in Firefox (Opera and Konqeror ran them both at a good speed). So I did the browser detect to help the script run at its fastest in all browsers.

There were a few other things that were browser-specific, but for all those I was able to use object detection or other fall-back methods.

4 Posted by Matt Sandy on 25 July 2006 | Permalink

I have to say that I loved the first comment. It probably was one of the funniest things I have seen, because I remember in High School people used to do that... and the real-estate database (MLS - Multi Listings Database) forces you to use internet explorer... which is gay. I don't use browser-redirects, but I do like to read about how people solve their problems. Some good info.

5 Posted by ranjan on 25 July 2006 | Permalink

Tested on Linux
Firefox 1.5
Konqueror 3.5
Opera 9.0

6 Posted by Alex Lein on 25 July 2006 | Permalink

lol @ #1

This script will do quite nicely! I've had a few instances where browsers that do support the same objects or methods do so in a slightly different manner, and differentiating between them is sometimes necessary.

Opera for instance will return code 304 instead of 200 from an XMLHttpRequest if the file hasn't been updated with new information. Also, Firefox doesn't fire the readystatechanged event if the XMLHttpRequest is openned in "sync" (as opposed to async).

Finally, lol @ your comment about Safari version string not working! :D

7 Posted by David on 25 July 2006 | Permalink

The one time I've had to use a browser detect so far was the result of IE 5 ignoring the z-index on select boxes. This made it very hard to put tooltips on controls, as sometimes the tip would appear to be "behind" the selects.

8 Posted by Alan Bram on 26 July 2006 | Permalink

Maybe you should make it really hard to use, so that newbies can't figure it out.

9 Posted by Michiel on 26 July 2006 | Permalink

@David
You don't need browser detection in that case either. In the case of selects you can use the IFRAME trick in IE. Simply place an IFRAME behind the tooltip. All browsers will display it fine and the tooltip will be on top of the select.

10 Posted by Antonio on 26 July 2006 | Permalink

My first reaction was to look at the date. Nope. Not April 1st.

After been completely convinced that browser detection is the work of the devil, I can't think of a use for this script. Probably because while not a newbie, I'm not a pro neither.

Could you point to some example? Or should I wait for the book? ;-)

11 Posted by David on 26 July 2006 | Permalink

@Michiel:
From my testing, the iframe trick only worked in IE5.5 and above. IE5.0 still had bleed-through. So, I ended up doing a three-step fix: if in IE less than 5.5, the selects are hidden when a tooltip goes over it; IE 5.5 uses the iframe trick; everything else uses CSS appropriately.

I hate supporting old versions of IE, because they lead to having to do this sort of guck. But, since good web design supports IE 5.0 (and, ideally, IE 4!), and discourages the old "this site best viewed in" trope, there's little incentive for average users to upgrade; so, I'm curious: at what point should we stop supporting IE <6?

12 Posted by Dustin Diaz on 26 July 2006 | Permalink

I haven't even viewed the source yet - but I'll assume it's a good one. I share your concerns on newbie developers get their hands on this one, but good for you for publishing it :) Indeed there are very few places you'll need it, but it will still come in handy for the appropriate time.

13 Posted by Binny V A on 27 July 2006 | Permalink

Don't be worried wether or not the newbies will use this technique. The already have a 'working' browser detection - most will stick to it. If they want a better one, chances are that they will find the object detection method before they find this script.

14 Posted by Jordan West on 27 July 2006 | Permalink

Great script ppk! I can see how you would be worried about newbies, but let me try to ease your mind. The average newbie who would try to use the script in all of the ridiculous ways you could think of, probably wouldn't know how. Most of them will try to initialize the object, and understand how it works, and be confused by all the brackets and braces. I am glad you published this though because i see some good uses for it, and it is a very well written, concise script.

15 Posted by Lon on 27 July 2006 | Permalink

I really don't like the condescending tone of the article. It makes me wonder whether PPK is "a pedant ventje". Pardon my dutch.

Besides that the script is hard to understand; partly because of illogical names, partly because of methods having side-effects.

16 Posted by Doeke Zanstra on 27 July 2006 | Permalink

Nice script. Can't think of something to use it for, but it can be a life saver when one runs into a browser specific problem.

You guys may also like this one:
http://37signals.com/svn/archives2/browser_selectors_in_css.php

17 Posted by Doeke Zanstra on 27 July 2006 | Permalink

Camino (using Gecko) and OmniWeb (using WebKit) on Mac isn't in your list yet. Here's the data (I've tested it on Camino 1.0):

{ string: navigator.vendor,
subString: "Camino",
identity: "Camino"
}
,
{ string: navigator.userAgent,
subString: "OmniWeb",
versionSearch: "OmniWeb/",
identity: "OmniWeb"
},

18 Posted by Joe D'Andrea on 1 August 2006 | Permalink

I'm debating whether or not to use browser detection to help make a style adjustment for Opera. (See http://test.joesapt.net/opera for the scoop - I might have stumbled upon a bug-a-boo.)

My spidey sense suggests "Don't do it! Look away!" Yet it's very tempting, and it arguably beats using CSS hacks (shudder).

19 Posted by Joe D'Andrea on 1 August 2006 | Permalink

Whoops - I just noticed the CSS browser selector in the comments. Hey now! :-)

20 Posted by Tristan Gray on 3 August 2006 | Permalink

Well... I'm not sure if they are using your script but here's an example of something quite frustrating.

http://www.mapleglobal.com/

21 Posted by David on 3 August 2006 | Permalink

Loaded that site in IE to look at the code--it's not using PPK's script (it checks navigator.appName and navigator.plugins.length, which is probably their response to browsers allowing you to set the appName).

22 Posted by Peter on 16 August 2006 | Permalink

So, how about this? We are trying to get away from having multiple pages for our regular page versus mobile users. How can we detect those browsers, and then program our stylesheet accordingly?

23 Posted by y5 on 17 August 2006 | Permalink

Peter: Use conditional comments.

http://www.quirksmode.org/css/condcom.html
http://www.456bereastreet.com/archive/200511/valid_downlevelrevealed_conditional_comments/

24 Posted by Dave Cardwell on 18 August 2006 | Permalink

I have created a plugin for the popular jQuery library inspired by this work. Thank you, PPK.

http://davecardwell.co.uk/geekery/javascript/jquery/jqbrowser/