Exhausted by sniffing
September 9, 2002
Feedback Farm
Have something to say about this article? Let us know below and your post might be the Post of the Month! Please read our Official Rules and Sponsor List.
Forums
Want to dig even deeper? Post to the new MacEdition Forums!
Every so often, you encounter a Web site that is completely, utterly broken. Oh, it works in Internet Explorer for Windows, of course. Of course! But in the browser you use – be it Mozilla, Opera, iCab, OmniWeb or Internet Explorer for Mac OS – you can't get it to work. Perhaps the links don’t work, or the drop-down menus, or maybe you just get a blank page or a crashing browser.
I’m here to tell you that the problem is often not bad HTML, or broken JavaScript, or proprietary extensions to CSS. More often than not, it seems, the problem is stupid assumptions by the site designer. In an attempt to get around browser bugs or differences in browsers’ support for Web standards, they’ve put in a browser sniffer to send appropriate content to each browser. Unfortunately, not all Web authors have done this sensibly. Some make overly restrictive assumptions about their audience, and so they end up locking out anyone outside their narrow view of the browser world. Their ham-fisted attempts at sniffing out your browser are based on enumerating the browsers they’ve heard of, instead of using an exhaustive approach that accommodates browsers that they haven’t heard of or that don’t yet exist.
As you’d probably guess, I think that non-exhaustive sniffer scripts are idiotic. Non-exhaustive sniffing scripts shut out search engines (and unless you’re completely totalitarian and autocratic, I bet you don’t really want to do that). They also shut out many less common browsers like Opera, iCab, OmniWeb, not to mention users of non-standard devices like PDAs, phones, and WebTV units.
Of course, it’s not always the fault of the Web author. Many people do not write their own browser sniffer from scratch, they use somebody else’s. There’s no sense duplicating effort. Unfortunately, even scripts available from reputable sources don’t always handle unusual browsers, and in some cases they identify unusual browsers incorrectly. For example, the sniffer script suggested by About.com lists itself as being compatible with Internet Explorer and Netscape Versions 3.0 and above, for Windows and Mac. The sad thing is, the script works in Opera, iCab, Mozilla and who knows what else, it just doesn’t do much in them. It can tell if you’re using a Mac, but not much else unless you’ve set the browser to pretend to be something else. And oh yes, it will identify Netscape 6 but not Mozilla. Good one, folks.
Other sniffers do a lot better. WebReference’s offering does a pretty good job of detecting things like Opera. As would be expected from a script that’s closely related to the (outdated) one on mozilla.org, it also correctly identifies all Mozilla/Gecko-based browsers as such, including Chimera, Galeon and Netscape 6+, as well as Mozilla itself. About.com’s script doesn’t do this. Unfortunately, most sniffer scripts don’t handle Mac-specific browsers like OmniWeb or iCab very well, so Web authors with large Mac-using audiences need to take extra care if they want to use JavaScript to serve different content to different browsers.
Do it right and ELSE
I’m not suggesting you should try to work out ways to identify every browser
individually. Many browsers don’t send sensible information in the
identification properties like navigator.appName
. Many others
allow you to set them up to pretend to be something else. As regular
readers would know, while I understand the rationale for browser spoofing,
I also think it can be
counterproductive. If your browser has different bugs to the one it is
spoofing, you might find that you are being served vastly inappropriate
content. And if minor browsers don’t identify themselves correctly, lazy
Web developers will just assume they are dealing with two
platforms, two browsers, two versions. That’s no way to get Web
standards working.
No, the right way involves three things. First, don’t rely on what the
browser says it is; use information about what it does.
For example, don’t ask for the appName
property, check for functionality. If
the browser supports document.layers
, that means it’s
Netscape 4.x or
OmniWeb. If it supports
document.all, it’s a version of Internet Explorer (or iCab, as far as I can
tell). If it supports GetElementById
, it could be any number of browsers
with good DOM
support. If an iCab user is spoofing as Netscape 4, that
doesn’t mean that it supports document.layers
, and you’ll get
ugly results if you assume that it does support it. Don’t take the browser
identification properties as gospel.
Second, don’t assume that support of one property (say,
getElementById
) implies the support of another feature –
especially if that other feature involves a whole other set of standards
like CSS or XML support. This is one of the reasons that Tantek’s high-pass
filter appears to fail in
iCab. iCab passes the high-pass filter, but doesn’t support many of the Web
standards that people might expect of a browser that passes it, like
CSS1
floats, or just about anything specific to
CSS2, including positioning.
Third, make sure you have a catch-all case for all the browser that you haven’t thought of or have never heard of. I really shouldn’t have to tell you this – it’s Computer Programming Concepts 101. Alas, it seems too many Web programmers haven’t thought through the basic logic. I know that big Web designers have made this very mistake, including the bright sparks who built bmwusa.com. Alerted by an email from a sharp-eyed reader, I discovered the following JavaScript code included as part of bmwusa.com’s sniffer script:
if (navigator.appVersion.indexOf("Macintosh") == -1) {
document.domain = "bmwusa.com"; }
function reStore() {if
(document.layers){top.location = "http://bmwusa.com/welcome.cfm"; }}
function handleResize() {if (!document.all) { location.reload(); return
true;}}
This code sends non-Mac users to bmwusa.com,
instead of www.bmwusa.com. It
then sets up functions that makes Netscape 4 (document.layers
) and any
browser that emulates it (mainly OmniWeb) reload the page. It also has a
handleResize
function that reloads the page if document.all
is not true – that is, any browser other than IE and browsers that emulate it (mainly
iCab). I’m not quite sure what they are trying to achieve, but they have
succeeded in locking out Mozilla users and crashing Opera. To think people
get paid for this sort of tripe. And while I’m not in the market
for a BMW, especially not one in the US, I can see that this might turn off
a few potential buyers.
What’s particularly sad is that they probably don’t perceive it as a problem. After all, all the traffic in their logs will be from the browsers they do support. They probably think that everyone uses IE or Netscape 4, because that’s all that can get into the site.
The problem with bmwusa.com is that they didn’t have an “everyone else” category. Their script just didn’t allow for browsers outside their narrow view of the Web. They needed a true “else” statement, just as is shown in the mozilla.org script.
KISS and markup
Having told you how to sniff the right way, I should point out that I question whether sniffing is necessary in many of the situations that it is used. Is your content really so complex that you need to sniff browsers to serve correct content? Would you be better off using a server-side sniffer instead of relying on JavaScript features to determine support for non-JavaScript features? Is the browser sniffer only there because GoLive or FrontPage or whatever package you are using puts it in by default? Are you sniffing out the different browsers only because they have different font size interpretations? Give over, the world won’t end if different browsers have subtly different linespacing or font rendering.
Sniff if you must, but it’s nicer to use a tissue, isn’t it?