homepage Welcome to WebmasterWorld Guest from 174.129.103.100
register, free tools, login, search, pro membership, help, library, announcements, recent posts, open posts,
Become a Pro Member
Home / Forums Index / Code, Content, and Presentation / JavaScript and AJAX
Forum Library, Charter, Moderator: open

JavaScript and AJAX Forum

    
Javascript Browser Detector almost complete!
Superfrappe




msg:1493590
 1:17 pm on Aug 13, 2003 (gmt 0)

Hi all,

This is my first post on this particular board, and I look forward to talking with you guys and gals in the future.

Here's my latest deal:

I have a javascript browser sniffer that i need to detect each browser seperately. I had a different browser detector i was using before, but it couldn't tell the difference between Opera and Mozilla. Therefore, I am now using a new one that I've been tweaking over the last 24 hours, but I still can't get it just right.

I have a new site I'm working on, and it's coded completely with XHTML, CSS, JavaScript, and Coldfusion. Especially because of the CSS2 and the XHTML, every browser and version renders my code differently. The most important browsers on my list right now, are IE, Netscape 4.8, Netscape 5+, Opera, and Unix.

So far, I can get the Opera detector to work fine, but that's it. When I activate the IE detector (code at the bottom) the Netscape rendering goes haywire, and vice versa when I activate the IE detector. Seems the IE detector is actually reading the Netscape CSS! Argh!

I've also been having trouble when trying to differentiate the versions of Netscape. The reson the two netscape versions are so important is because we ran Webtrends and found out 30% of our visitors are still using Netscape 4.8! Good grief!

Here's the code, and sorry for such a long first post! Thanks in advance for your help.

// JavaScript Document

var detect = navigator.userAgent.toLowerCase();
var OS,browser,version,total,thestring;

if (checkIt('konqueror'))
{
browser = "Konqueror";
OS = "Linux";
}
else if (checkIt('safari')) browser = "Safari";
else if (checkIt('omniweb')) browser = "OmniWeb";
else if (checkIt('opera')) browser = "Opera";
else if (checkIt('webtv')) browser = "WebTV";
else if (checkIt('icab')) browser = "iCab";
else if (checkIt('msie')) browser = "IE";
else if (!checkIt('compatible'))
{
browser = "Netscape"
version = detect.charAt(8);
}
else browser = "unknown browser";

if (!version) version = detect.charAt(place + thestring.length);

if (!OS)
{
if (checkIt('linux')) OS = "Linux";
else if (checkIt('x11')) OS = "Unix";
else if (checkIt('mac')) OS = "Mac";
else if (checkIt('win')) OS = "Win";
else OS = "unknown operating system";
}

function checkIt(string)
{
place = detect.indexOf(string) + 1;
thestring = string;
return place;
}

if (OS == "Win" && browser == "Opera")
{
document.location.href='ns4/index.cfm'; document.location.reload;
}
else if (OS == "Win" && browser == "Netscape" && version == 4.8)
{
document.location.href='ns4/index.cfm'; document.location.reload;
}
else if (OS == "Win" && browser == "Netscape" && version == 7)
{
document.write('<link rel="stylesheet" type="text/css" href="css/ieNavStyles.css" title="style"> <STYLE title="currentStyle" type="text/css" media="all">@import url(css/ieNavStyles.css);</STYLE>');
}
else (OS == "Win" && browser == "IE" && version == 6)
{
document.write('<link rel="stylesheet" type="text/css" href="css/ieWinStyles.css" title="style"> <STYLE title="currentStyle" type="text/css" media="all">@import url(css/ieWinStyles.css);</STYLE>');
}

 

Hester




msg:1493591
 3:15 pm on Aug 13, 2003 (gmt 0)

This is not good. What if Opera users are setting their UA string to IE5? Or IE6? Also browser versions change so much - even between the same numbers - eg: Mozilla 1.4 beta is not the same as 1.4 final.

What you should do is much simpler.

1. Allow all versions of Netscape 4 from 4.9 downwards to be given the page without any stylesheet. This means they get the information but not the styles, so you can use all the commands that foul up in that browser. This is now common practice on many sites.

2. Sniff for the browser's ability to deal with the DOM properly. If it passes, then the browser is a "version 5" and can handle CSS fine.

To do this use this code:

if (document.getElementById && document.createElement)...

3. Any differences are slight and can be handled by hacks in the stylesheet. Are you detecting browsers and manually creating a separate stylesheet for each one?! You only need ONE.

Your HTML should be able to 'work with any browser' this way. Otherwise you'll be programming like mad every time a new version of a new browser comes out.

drbrain




msg:1493592
 3:17 pm on Aug 13, 2003 (gmt 0)

Your script is not future-proofed, and you don't correctly recognize the different browser versions available. You should read the Devedge Browser Detection [devedge.netscape.com] page at devedge, and probably should instead use Object-based detection [devedge.netscape.com] instead of user-agent based detection, because Opera, Gecko, and other browsers can be easily configured to emulate IE.

There's no reason to write completely different style sheets for different browsers. If you write them to degrade properly, you'll cut your maintenance by a great deal. Come visit us over in the CSS Forum [webmasterworld.com], we'll teach you a bunch.

Even with this script, you'll be giving incorrect style information to users of standards-compliant browsers. Those should be the fall-through case, not IE. You make your job easier by coding to the common standard, rather than making it work for IE, then trying to support every browser that doesn't perfectly emulate IE's quirks.


if (OS == "Win" && browser == "Opera") {
document.location.href='ns4/index.cfm'; document.location.reload;

Opera 7 is much more like Gecko and Safari in capability than like NS4. This will give degraded content to users of a capable browser.


} else if (OS == "Win" && browser == "Netscape" && version == 4.8) {
document.location.href='ns4/index.cfm'; document.location.reload;

People are using more than version 4.8 of Netscape 4, and on platforms other than Windows. This will give incorrect content to users who aren't using this exact version/OS.


} else if (OS == "Win" && browser == "Netscape" && version == 7) {
document.write('<link rel="stylesheet" type="text/css" href="css/ieNavStyles.css" title="style"> <STYLE title="currentStyle" type="text/css" media="all">@import url(css/ieNavStyles.css);</STYLE>');

It would be more correct to sniff for the string 'Gecko' than to sniff for version == 7, how will you detect Mozilla or other Gecko-based browsers? Furthermore, this won't work for non-windows Gecko users.


} else (OS == "Win" && browser == "IE" && version == 6) {
document.write('<link rel="stylesheet" type="text/css" href="css/ieWinStyles.css" title="style"> <STYLE title="currentStyle" type="text/css" media="all">@import url(css/ieWinStyles.css);</STYLE>');
}

That's a syntax error, there isn't a test expression for an else. You should be giving everybody else the style sheets you give above to Netscape 7, because they're more alike than they are like IE.

BlobFisk




msg:1493593
 3:47 pm on Aug 13, 2003 (gmt 0)

Just wanted to say

Welcome to WebmasterWorld, Superfrappe!

Superfrappe




msg:1493594
 7:56 pm on Aug 13, 2003 (gmt 0)

To do this use this code:

if (document.getElementById && document.createElement)...

3. Any differences are slight and can be handled by hacks in the stylesheet. Are you detecting browsers and manually creating a separate stylesheet for each one?! You only need ONE.

Thanks for your reply Hester. So if I use that line of code, how is it that I only need one stlysheet? see, when I came on board at this college a few months ago, I discoverd the old web dev guy had used a browser detect script that pointed to 6 different stylesheets. This is what I started to do when I began building their IT site, but since the IT site is coded far more advanced than the older college site, the old browser detect/point to one of many stylesheets thing is not happenin'. So are you saying the best way is to detect by feature, and point to ONE sheet? How can I do tweaks for different browsers in one sheet? Thanks again Hester!

Your script is not future-proofed, and you don't correctly recognize the different browser versions available. You should read the Devedge Browser Detection page at devedge, and probably should instead use Object-based detection instead of user-agent based detection, because Opera, Gecko, and other browsers can be easily configured to emulate IE.

Hey drbrain, thanks for your reply. I completely understand where you're coming from, and appreciate the time you took to go through my code piece by piece to educate me on what needs to be done, and what not to do. I'm close to the end of the Devedge Browser Detection article, and wow that is just what i needed. I feel like I've been missing something in my web dev years, and just hopped on the train!

One thing though, and please bear with me, because maybe I haven't gotten to that part yet on the Develge page yet (i'm at the end where the examples are, and trying them out) but I Netscape 7 and IE 6 are reading my page differently, so i need to have 2 seperate stylesheets for them. (or do i?) ...but it seems the feature detection treats those two versions of the browser as the same?

I greatly appreciate your time and comments. Thanks drbrain!

Just wanted to say
Welcome to WebmasterWorld, Superfrappe!

A big thanks to ya, BlobFisk!

- Frappe

Hester




msg:1493595
 10:27 am on Aug 14, 2003 (gmt 0)

Forgive me, the code is for using Javascript that copes with all browsers (so you don't need a browser detection code.) The details are worth reading about because they explain why browser detects are a bad idea: [xs4all.nl ]

How can I do tweaks for different browsers in one sheet?

What you can do is give code that works for one browser, then add a 'hack' to give code to another browser in the same stylesheet. The hack uses code the other browsers ignore, but the one it's meant for. That one then acts on the code.

So you can build up your stylesheet giving hacks to each browser - Mozilla, Opera, Netscape 4 (if you must style it), IE/Win and IE/Mac.

To learn how to use hacks and see a table of which ones work, go here: [centricle.com ]

The main point is that if your code is good enough (following the W3C standards) it should work 95% in all browsers to start with. Then all you need is to use hacks to tweak the layout because of known browser differences or bugs.

I discoverd the old web dev guy had used a browser detect script that pointed to 6 different stylesheets.

Madness! :)

Superfrappe




msg:1493596
 2:30 pm on Aug 14, 2003 (gmt 0)

Hester, thanks so much for that info! I'm getting closer and closer to finally understanding all this. The one thing I'm still not sure about is exactly how to have only ONE stylesheet. Could you give me any examples I can learn from? How can I have one sheet that has different tweaks for Mozilla, Opera, IE/Win and IE/Mac? Oh, and as for right now, anything that can't read the CSS correctly (NS 4), i still have pointing to a mock site made w/ old fashioned html and tables. Is this wrong to do?

Thanks again Hester, you've been a great help pal. :)

Hester




msg:1493597
 3:00 pm on Aug 14, 2003 (gmt 0)

OK, consider this example:

#test {width:200px;}

html[xmlns] #test {width:190px;}

It goes in your stylesheet to reference a piece of HTML like this:

<div id="test">I'm 200px wide in Opera and IE, but only 190px wide in Mozilla and Netscape 6 and 7!</div>

The stylesheet first gives the div a width of 200px. But along comes a line of code that only Mozilla (and therefore Netscape 6 & 7) recognises. So in those browsers, the width gets changed to 190px! But in IE and Opera, the width stays the same! Because they skip over the line they don't understand.

So you can make a stylesheet that deals with all these different browsers, by declaring things twice! So only one stylesheet is needed.

The only issue with these hacks is this: what if a new browser version suddenly supports the code? So use them sparingly.

drbrain




msg:1493598
 3:28 pm on Aug 14, 2003 (gmt 0)

You'll also want to validate your pages at [validator.w3.org...] be sure to include a DOCTYPE with URL at the top of your page like:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

Or even better, drop all your <b> and <i> and <font>, and use:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

You can find more information on doctypes here on WW, or through <search engine of choice>.

The doctype will make IE6 be in "standards mode" meaning it will behave much more like Gecko (Mozilla, NS7, etc), Opera, Safari, and other standards-mode browsers.

gph




msg:1493599
 4:05 pm on Aug 14, 2003 (gmt 0)

I agree that browser sniffing is the wrong approach. Having said that I find it necessary to sniff for Opera 6.

Any js bells and whistles I use are DOM only. Opera 6 can't handle DOM js after page load but returns true on document.getElementById. This is in a basic js file that gets a link in the page.

function not_ope() {
var ua = navigator.userAgent.toLowerCase()
return parseFloat(ua.charAt(ua.indexOf('opera') + 6)) <= 6 ? 0 : 1
}

if (typeof window.opera != 'undefined' ? not_ope() : document.getElementById) {
document.write('<\script type="text/javas\cript" src="dom.js" ></s\cript>')
}

Superfrappe




msg:1493600
 7:07 pm on Aug 15, 2003 (gmt 0)

Well, you guys have helped me with this quite a bit!

My last remaining issue (i hope), is that Opera still can't read my page right, so i need to be able to only detect Opera and point it to either a seperate sheet, or figure out how to hack in some styles on my ONE sheet so that only Opera can see them, which apparently i can't do, since Opera is reading the styles that are meant for Mozilla.

gph, I tried your code, but it still won't work for me.. am I missing something? I just really need to deal w/ Opera. Either i have to redirect it, or i need a way to write it's OWN css... Help!

Thanks :)

gph




msg:1493601
 7:52 pm on Aug 15, 2003 (gmt 0)

try this:

<html>
<head>
<title></title>
<script>
if (typeof window.opera != 'undefined') {
document.write("Hi, I'm Opera :)<br>")
}

function not_ope() {
var ua = navigator.userAgent.toLowerCase()
return parseFloat(ua.charAt(ua.indexOf('opera') + 6)) <= 6 ? 0 : 1
}

if (typeof window.opera != 'undefined' ? not_ope() : document.getElementById) {
document.write("I'm a DOM browser :)")
} else {
document.write("What's a DOM?")
}
</script>
</head>
<body>
</body>
</html>

<edit>
I used the wrong bracket in a smile :O
</edit>

[edited by: gph at 8:26 pm (utc) on Aug. 15, 2003]

gph




msg:1493602
 8:06 pm on Aug 15, 2003 (gmt 0)

By the way, it's not simple but you shouldn't need to detect Opera for CSS. Opera is CSS compliant. Rather than writing another CSS file I'd suggest making the one you have work in Opera.

I'm guessing that you did your CSS testing in IE. It seems like the best approach because IE is so dominant but IE isn't as compliant as Opera or Moz. It's easier to test in Moz or Opera then apply hacks for IE.

Superfrappe




msg:1493603
 8:57 pm on Aug 15, 2003 (gmt 0)

cool gph, that's very good advice.. i'll do that. i did do my css testing in IE, but i'm now convinced those days are over. i'm going to test in moz and opera now. thank you again for all your help. have a great weekend. :)

Duckula




msg:1493604
 9:21 pm on Aug 15, 2003 (gmt 0)

if (checkIt('konqueror'))
{
browser = "Konqueror";
OS = "Linux";
}

I don't know how far you want to go with your generalization, but KDE is not exclusive to Linux; it's more like for any *nix, and used too in Windows (very occasionally) through cygwin.

ratboy




msg:1493605
 6:27 pm on Aug 17, 2003 (gmt 0)

If you want a browser detection script that will not be fooled by any browser I know of you can get it here (it's pretty long, so it's easier to download, it has a few different scripts on it, complex to simple:

<edit>

But I agree with most of the posters, it's much better to do object/method testing. Doing a cascading test using that method is much more solid than trying to deliver different js for different browsers, that's a total pain.

I use browser detection primarily when a specific fix is required for a specific browser, like if you have a left navigation bar made out of stacked <a > tags with css property set to display:block, which isn't supported by IE 4 for example, in that case I would have the script insert a <br /> after each <a> in the list.

Personally I'm not a fan of using the @ method because it delivers a really ugly page if you had most of your styling in the called stylesheet, I like to try to support around 99.9% of a site's visitors if practically possible. Or you can do two stylesheets, a basic one, and one that has the complicated css 2 stuff on it. but then you have to maintain different stylesheets, I'm too lazy to do that.

For netscape 4x you can just escape the css with this:

css code that works on ns4
/*/*/
css code that won't work in ns4x, or that crashes it, like borders on table cells, various margin problems, and so on.

/*/*/ escapes the code, nothing after that is read by ns4

That has to be the last part of the stylesheet, ns4 ignores everything after that.

[edited by: tedster at 7:00 pm (utc) on Aug. 17, 2003]

ratboy




msg:1493606
 7:13 pm on Aug 17, 2003 (gmt 0)

Here's the complex script:

var d, dom, ie, ienu, ie4, ie5, ie5x, ie6, moz, moznu, mac, win, old, lin,
ie5mac, ie5xwin, op, opnu, op4, op5, op6, op7, konq, saf, saf_num;

//variable initialization

d = document;
n = navigator;
nav = n.appVersion;
nan = n.appName;
nua = n.userAgent;
win = ( nav.indexOf( 'Win' )!= -1 );
mac = ( nav.indexOf( 'Mac' )!= -1 );
lin = ( na.indexOf( 'Linux' )!= -1 );

/*
d.layers is preferred method to test for NS 4.x over placing a boolean value into a
ns4 variable as we do with the other browsers due to netscape 4x bugs
*/

if (!d.layers ){
dom = ( d.getElementById ); // useful for other functions often, for method testing
old = ( nav.substring( 0, 1 ) < 4 );
op = ( nua.indexOf( 'Opera' )!= -1 );
moz = ( nua.indexOf( 'Gecko' )!= -1 );
ie = ( d.all &&!op );
konq = ( nua.indexOf( 'Konqueror' )!= -1 );
saf = ( nua.indexOf( 'Safari' )!= -1 );

//test for opera first, that way the detector won't get caught on false identifying operas

if ( op ){
op_pos = nua.indexOf( 'Opera' );
opnu = nua.substr( ( op_pos + 6 ), 3 );
op5 = ( opnu.substring( 0, 1 ) == 5 );
op6 = ( opnu.substring( 0, 1 ) == 6 );
op7 = ( opnu.substring( 0, 1 ) == 7 );
}
//must test for safari before mozilla because safari nua string has 'gecko' in it.
else if ( saf ){
saf_pos = nua.indexOf( 'Safari' );
saf_nu = nua.substr( ( saf_pos + 7 ), 2 );
//note, as of 6-21-03 safari is still in beta, saf_nu was around 70, 60 for early releases
}
else if ( moz ){
/*
note: mozilla browsers can be id'ed by rv number, but if you are trying to id
the actual Netscape 6 or greater browsers safely, you will need to use the build date.
We will have that code up shortly. Netscape 7 uses a rv number of about 1.0.1, so
this technique won't work accurately for all gecko id'ing
*/

rv_pos = nua.indexOf( 'rv' );
moz_rv = nua.substr( ( rv_pos + 3 ), 3 ); // use this for main version, like 0.9, 1.0, 1.1, 1.2
moz_rv_sub = nua.substr( ( rv_pos + 7 ), 1 );
moz_rv_sub = moz_rv + moz_rv_sub; // use this if exact version is required, like 0.9.4, ie netscape 6.2
}
else if ( ie ){
ie_pos = nua.indexOf( 'MSIE' );
ienu = nua.substr( ( ie_pos + 5 ), 3 );
ie4 = (!dom ); /* remember, IE 4 does not have much DOM support, if any, but it's a very small part of the market */
ie5 = ( ienu.substring( 0, 1 ) == 5 );
ie6 = ( ienu.substring( 0, 1 ) == 6 );
}
else{}

/*
we have had reports of some browsers having problems if you don't close out the if/else if with an else, better safe than sorry
*/

/*
ie5x tests only for functionavlity. dom or ie5x would be default settings.
Opera will register true in this test if set to identify as IE 5
*/

ie5x = ( d.all && dom );

/*
mac opera registers false here. Remember, IE for Mac has nothing to do with IE for windows, it's a different
code base completely, functionally it's closest to Opera 5 or 6. Having javascript run on this correctly is a
hit and miss proposition; never assume your code will work on IE Mac, always test it on a Mac, both OS 9 and OS X
*/
ie5mac = ( mac && ie5 );
ie5xwin = ( win && ie5x );
}

ratboy




msg:1493607
 7:15 pm on Aug 17, 2003 (gmt 0)

Here's our light version, usually more than enough for most apps

var d, dom, ie, ie4, ie5x, moz, mac, win, lin, old, ie5mac, ie5xwin, op;

d = document;
n = navigator;
na = n.appVersion;
nua = n.userAgent;
win = ( na.indexOf( 'Win' )!= -1 );
mac = ( na.indexOf( 'Mac' )!= -1 );
lin = ( na.indexOf( 'Linux' )!= -1 );

if (!d.layers ){
dom = ( d.getElementById );
op = ( nua.indexOf( 'Opera' )!= -1 );
konq = ( nua.indexOf( 'Konqueror' )!= -1 );
saf = ( nua.indexOf( 'Safari' )!= -1 );
moz = ( nua.indexOf( 'Gecko' )!= -1 );// will be true for safari as well
ie = ( d.all &&!op );
ie4 = ( ie &&!dom );

/*
ie5x tests only for functionality. ( dom¦¦ie5x ) would be default settings.
Opera will register true in this test if set to identify as IE 5
*/

ie5x = ( d.all && dom );
ie5mac = ( mac && ie5x );
ie5xwin = ( win && ie5x );
}

Global Options:
 top home search open messages active posts  
 

Home / Forums Index / Code, Content, and Presentation / JavaScript and AJAX
rss feed

All trademarks and copyrights held by respective owners. Member comments are owned by the poster.
Home ¦ Free Tools ¦ Terms of Service ¦ Privacy Policy ¦ Report Problem ¦ About ¦ Library ¦ Newsletter
WebmasterWorld is a Developer Shed Community owned by Jim Boykin.
© Webmaster World 1996-2014 all rights reserved