This topic has been closed. No new entries allowed.
Reason: You can now post comments on articles on Dev Opera
You need to be logged in to post in the forums. If you do not have an account, please sign up first.
Using capability detection
Browser sniffing causes much more harm than good, claims this article, showing in practical examples how to let your script adapt to the different browser capabilities you actually need.( Read the article )
--
My blog: miscoded
Stupid code from major websites uncovered and criticised
Contribute site fixes! - OTW&TA- all sites must work
My blog: miscoded
Stupid code from major websites uncovered and criticised
Contribute site fixes! - OTW&TA- all sites must work
I'm glad there's finally an article one can reference about this matter, because it's driving me nuts to see all this crazy browser sniffing code still alive and actively maintained on major websites. Web developers employing browser sniffing code in their scripts (either client or server side) should have their hands tied to their backs, their computer removed from their posession, loose their job and never be allowed to write a single line of code in their entire life, ever again.
«He's a loathsome offensive brute, yet I can't look away»
Although this is a very usefull article your 'classic example' can be much improved upon as I explained in my blogpost at http://therealcrisp.xs4all.nl/blog/2006/12/03/capability-detection-the-better-way/
Originally posted by crisp:
your 'classic example' can be much improved upon
Certainly a nice way to do it

If I'm allowed to edit articles once "published" (haven't quite figured out all corners of dev.opera yet) I'll add a note with a link to your post.
--
My blog: miscoded
Stupid code from major websites uncovered and criticised
Contribute site fixes! - OTW&TA- all sites must work
My blog: miscoded
Stupid code from major websites uncovered and criticised
Contribute site fixes! - OTW&TA- all sites must work
Playing with your example script 
1.
Not that this is needed any more, but since we're here anyway
...
The basic check will get Netescape 4, Escape 4, OmniWeb 4.2, HotJava.
Testing for basic support would require you to create a DIV (or LAYER), positioned absolutely, with an ID, and then check for it. This would get Netscape 4, Escape 4, OmniWeb 4.2 (HotJava does not actually support it although it tests true if you just check for the collection).
Testing for complete layers support would be something like this:
navigator.capOldDOMNN = ( document.layers && window.Layer && ( new Layer(1) ) ) ? true : false;
That would get Netscape 4 and Escape 4 (and iirc, throw an error in OmniWeb 4.2 because the constructor does not work, so in general I used to check for one of the things below).
There are also other parts of the old NS4 DOM that related to stylesheets, which can be detected - since JavaScript could create stylesheets on the fly using a syntax that reminds me of Håkon's original CSS proposals:
document.classes.foo.all.color = '#00ff00';
document.classes.foo.h1.color = '#ff9900';
document.ids.baz.fontSize = '12pt';
document.tags.p.margin = '10px';
Note that I am not recommending that anyone actually bother to use this (in fact, I recommend that you look at it, feel nauseous, and never touch it again), I am just putting it here for the sake of interest.
2.
Although it works, this splitting of script tags is not the "correct" approach:
The correct way to do it is to escape the / characters, so there is no </ or </script> visible to the parser:
document.write('<script type="text\/vbscript">navigator.capVBScript = True<\/script>');
3.
Note that the browsers you are trying to protect will throw an error here, and may display their error dialogs. Anyone still using these browsers probably needs those dialogs as a reminder that their browser is severely out of date
but you should be able protect them by hiding errors first:
window.onerror = function () { return true; };

1.
Originally posted by hallvors:
navigator.capOldDOMNN = ( document.layers ) ? true : false ;
// I don't know enough about document.layers DOM to truly test for it.
Not that this is needed any more, but since we're here anyway
...The basic check will get Netescape 4, Escape 4, OmniWeb 4.2, HotJava.
Testing for basic support would require you to create a DIV (or LAYER), positioned absolutely, with an ID, and then check for it. This would get Netscape 4, Escape 4, OmniWeb 4.2 (HotJava does not actually support it although it tests true if you just check for the collection).
Testing for complete layers support would be something like this:
navigator.capOldDOMNN = ( document.layers && window.Layer && ( new Layer(1) ) ) ? true : false;
That would get Netscape 4 and Escape 4 (and iirc, throw an error in OmniWeb 4.2 because the constructor does not work, so in general I used to check for one of the things below).
There are also other parts of the old NS4 DOM that related to stylesheets, which can be detected - since JavaScript could create stylesheets on the fly using a syntax that reminds me of Håkon's original CSS proposals:
document.classes.foo.all.color = '#00ff00';
document.classes.foo.h1.color = '#ff9900';
document.ids.baz.fontSize = '12pt';
document.tags.p.margin = '10px';
Note that I am not recommending that anyone actually bother to use this (in fact, I recommend that you look at it, feel nauseous, and never touch it again), I am just putting it here for the sake of interest.
2.
Although it works, this splitting of script tags is not the "correct" approach:
Originally posted by hallvors:
document.write('<scr' + 'ipt type="text/vbscript">navigator.capVBScript = True</scr' + 'ipt>');
The correct way to do it is to escape the / characters, so there is no </ or </script> visible to the parser:
document.write('<script type="text\/vbscript">navigator.capVBScript = True<\/script>');
3.
Originally posted by hallvors:
eval('try{ navigator.capTryCatch = true; }catch(e){}');
Note that the browsers you are trying to protect will throw an error here, and may display their error dialogs. Anyone still using these browsers probably needs those dialogs as a reminder that their browser is severely out of date
but you should be able protect them by hiding errors first:window.onerror = function () { return true; };
Core QA
Opera Software ASA
Opera Software ASA
There is also an article from Apple on Object Detection <a href="http://developer.apple.com/internet/webcontent/objectdetection.html">here</a>.
<q>Knowledge speaks, but wisdom listens.</q> - Jimi Hendrix
David Storey, Chief Web Opener, Product Manager Opera Dragonfly, Opera Software ASA
David Storey, Chief Web Opener, Product Manager Opera Dragonfly, Opera Software ASA
Good article here.
I'd add to that two suggestions:
1) Use typeof for checking existence:
<pre>
var hasTimeout = typeof req.ontimeout != "undefined";
</pre>
The typeof operator will swallow errors that are otherwise caused by GetValue when accessing the same named property in IE.
2) Avoid the <code>in</code> operator for host objects. Host objects use a yet-unstandardized "catchall" behavior to "catch" property names during get access, returning the value. Unfortunately, implementations vary. Even within one browser, two objects may have different type of catchall behavior. When "get" catchall behavior is implemented and "has" catchall is not, the result is an object that, to its user, appears inconsistent, contradicting itself by reporting that it does not have the property while returning the property on get access.
Catchall Example:
<pre>
// In Firefox 3.6 and below:
var p = navigator.plugins, ss = "Shockwave Flash";
s in p; // false
p[ss]; // [object Plugin]
// In Firefox 3.6 and below:
var f = document.forms[0], ss = "0";
s in f; // false;
f[ss]; // [object HTMLInputElement]
// In IE 8 and below:
var s = document.styleSheets, ii = "9999";
i in s; // true;
s[ii]; // Error.
</pre>
The Apple article mentioned in the previous comment is clearly no good. The author was just beginning to grasp the concept. Look:
<pre>
// maybe headed for trouble
if (document.body.scrollTop) {
// statements that work with scrollTop property
}
</pre>
The problem is that when <code>scrollTop</code> is <code>0</code> that the <code>if</code> statement will evaluate to false. This is not desirable and clearly an oversight of the author.
Another article:
http://jibbering.com/faq/notes/detect-browser/
I'd add to that two suggestions:
1) Use typeof for checking existence:
<pre>
var hasTimeout = typeof req.ontimeout != "undefined";
</pre>
The typeof operator will swallow errors that are otherwise caused by GetValue when accessing the same named property in IE.
2) Avoid the <code>in</code> operator for host objects. Host objects use a yet-unstandardized "catchall" behavior to "catch" property names during get access, returning the value. Unfortunately, implementations vary. Even within one browser, two objects may have different type of catchall behavior. When "get" catchall behavior is implemented and "has" catchall is not, the result is an object that, to its user, appears inconsistent, contradicting itself by reporting that it does not have the property while returning the property on get access.
Catchall Example:
<pre>
// In Firefox 3.6 and below:
var p = navigator.plugins, ss = "Shockwave Flash";
s in p; // false
p[ss]; // [object Plugin]
// In Firefox 3.6 and below:
var f = document.forms[0], ss = "0";
s in f; // false;
f[ss]; // [object HTMLInputElement]
// In IE 8 and below:
var s = document.styleSheets, ii = "9999";
i in s; // true;
s[ii]; // Error.
</pre>
The Apple article mentioned in the previous comment is clearly no good. The author was just beginning to grasp the concept. Look:
<pre>
// maybe headed for trouble
if (document.body.scrollTop) {
// statements that work with scrollTop property
}
</pre>
The problem is that when <code>scrollTop</code> is <code>0</code> that the <code>if</code> statement will evaluate to false. This is not desirable and clearly an oversight of the author.
Another article:
http://jibbering.com/faq/notes/detect-browser/