GEHC JavaScript
Week 6
Browser Compatibility
Browsers used for samples and examples:
MSIE 6.0.2
Navigator 4.79
Navigator 6.2.3
Opera 6.05
Based on what is possible to do in some browsers, you can often run into browser
incompatibilities that can hit you when you least expect it - usually it is
because you do most of your development in one browser, and make sure everything
works there, then either you or a web user tries the page with another browser
and you learn that you need to make changes to overcome differences.
The perfect example has nothing to do with JavaScript, and that is the marquis
tag in MSIE. There is no equivalent in Navigator, and so either a Java applet
or complicated JavaScript must be written to get the same effect. The blink
tag is another example - this God-awful tag works in Netscape 4 and lower only,
and not in any version of MSIE.
With just JS, you can have trouble, too. Given this code:
With this, we can change the image that is displayed in this place by doing
this in MSIE:
pinkimg.src = "blue.gif";
We've discussed this before - this is a recipe for disaster, but an easy trap to
fall into if you use MSIE most of the time.
** JS 6-1 - gives an example of code that works fine in MSIE but breaks in NN
In MSIE, img1 is a perfectly good global object - every named thing on a page
becomes an object that the JS code can refer to. However, in NN, just naming
something does no more than provide a way to access that object as a property of
the document object. Hence, the error that Netscape generates for this code:
img1 is not defined.
As an aside, note that the 6-1 code works in Opera 6.
There are two approaches to fixing a problem like this, and which you use may
depend on a few things. If you have a bunch of JS code that is already written
for MSIE, and you wish to adapt it to NN, then you can use one approach. If
you're aware of the problems before you start, you can write your code so that
it is compatible from the start.
To make the code compatible from the start, we have to use the "document." in
front of every object - both major browsers will work with this. However, if
you wish to eliminate the use of the document object, you can use the adaptation
method.
In that method, all we need to do is ensure that if an object does not exist,
that we make it exist. I'll use a function called "fixobjects". The first
version of fixobjects should work, based on what is mentioned in the text (page
42), but I had trouble with it:
function fixobjects()
{
if (!pink) pink = document.pink;
if (!blue) blue = document.blue;
}
If we run this in the onLoad event of the body tag, then we can make sure that
our code will work with either browser. In the case of MSIE, the pink and blue
object have value, so nothing changes. In NN, the pink and blue objects are
undefined, and we create them with the code.
Note that I do *not* use the var keyword here. By not using the var keyword, JS
creates these in NN with global scope. If I'd used the var keyword, then the
variables would have had local scope only and would have disappeared after the
fixobjects function is finished.
Now, as I said, this should work ... but it did not. This method would be ideal
because it seems to use core JS tests that have been around forever. But on the
first line, the "if (!img1)", I got the same "not defined" message that I got
before - so, only trust your tests, and never just your texts.
Here is code the uses the typeof operator, mentioned in Chapter 5. It is a
little more code, but works:
function fixobjects()
{
var type;
type = typeof pink;
if (type == "undefined") pink = document.pink;
type = typeof blue;
if (type == "undefined") blue = document.blue;
}
Here, I also don't use the var keyword, to ensure that everything is placed in a
global scope. But this time, I use the "typeof" on object to test. This
returns a string which describes the object - for a non-existent object, it
returns "undefined". We can test for this, and set up new objects if need be.
typeof exists in JS 1.1 and higher, which means it is not universal, but that
most browsers will support it. Again, if support in all browsers is crucial,
then "document." should be used.
** JS 6-2 - demonstrates the fixobjects that works, but also has a copy of the
one that does not - use your own browsers to test
We can expand on this basic concept to create objects that help us in our code.
"document.theform.city.value" is a lot to type. We can create an alias object
to shorten it:
var city = document.theform.city.value;
Now we can use "city" any time we need to examine or use the city.value. Note
that even in MSIE, there is no automatic "city" object because city is a member
of a form, so there is no conflict.
** JS 6-3 - Demonstrates the above process
However, this might be limiting.
** JS 6-4 - Shows possible errors
Remember, "city" now refers to a string, so other methods of the
document.theform.city object are not available. If you want them to be
available, make the city object equal to the city widget:
var city = document.theform.city;
Now, to access the value, you use "city.value" but you can also do
"city.focus()".
** JS 6-5 - Shows fix
Browser detection
-----------------
One other way of handling multiple browsers is to not even try to make your code
work with both browsers - but instead to have two versions of the code, one that
works for MSIE, and another that works with NN. To do this, you have to be able
to tell which browser you are working with. To that end, I'll use the detect()
function that is provided on the web page.
To use it, use this code:
This allows you to create your own object which will contain various pieces of
information about the browser that is in use.
var bd = new BrowserDetector(navigator.userAgent);
** detect.js
navigator.userAgent contains a string that the browser creates to identify
itself. The BrowserDetector function builds and returns an object that you can
get a copy of with the new keyword.
bd.browser will be "Unknown," "Netscape," "Lynx," "Opera," or "IE"
bd.platform will vary, but likely values are "Win95," "Win98," "Unix," etc.
bd.version is the full version, like 5.5 or 4.79
bd.majorver is the major version number, like 4 or 5
bd.minorver is the minor version number, like 5 or 79
** JS 6-6 - shows an example of BrowserDetect
** Image
The text outlines several strategies for handling multiple browsers:
Least-common denominator - this method is like those that we've discussed where
we would always use "document.", or avoid arrays, or only use JS1.0 compatible
code. If you stick with code that is all 1.0 or 1.1 compatible, you will cover
most browsers out there, though you will need to check your own logs to be sure.
This can also be quite limiting, so only do it if the need arises.
Defensive coding - write code that uses newer features, but go back and provide
your own versions of features for down-version browsers. This might be a good
approach if the bulk of your users use newer browsers, as you can roll out your
pages as they work in the latest versions, then go back and add new code to
handle old browsers as you are able.
** JS 6-7 - uses the browser detector to determine if the Array object can be
used
In this code, we set up functions to create an array in old-version browsers,
but hope to use the code that uses the Array object. If the Array object can be
used, we set "var myarray = new Array(10)" but if not, we use the makeArray
function, which is probably less efficient than using the Array object, to build
an array. Then we set myarray equal to the return value of the function. Once
the array is built, either way, we can use the same code to change and print the
contents.
The last major way of dealing with incompatibilities is to ignore the problem.
If you have hardly any NN2 users, or none at all, then don't bother coding for
NN2. Take a look at your browser stats and decide for yourself.
** browstat.html browstat2.html browstat3.html
Looking at just these lists, spread over a year, shows some real shifts. MSIE
5.5 started out strong but within a year was firmly replaced by MSIE 6. Mozilla
4 is relatively high, bu Mozilla 5 is catching up. Other older browsers are
still hanging on, like MSIE 3 and Mozilla 3, even a handful of WebTV users.
Opera 6 has increased as well.
Test, test, test
----------------
The only real way for you to know if your stuff is working is to test it. Bring
up your page in as many different versions of browsers as you can. If you
create test pages on your web site, you can quickly go to them from any
connected PC and check out a new browser. How did MSIE 3 render a table? Find
a machine with MSIE 3, load your page, and save the screen image. If nothin
else, at least you can see what it looks like. About to upgrade MSIE? Visit
all your test pages and get that screen image. A test page could be very
simple, just exercizing some basic HTML, or very complex.
** Display Tester
** Display Graphic
Note differences in Quote, Marquis, Subscript, Superscript. Note the different
line spacing in NN6. These small things can affect your page.
Detecting the JavaScript version
--------------------------------
If you decide to use features based not on browser type and version, but on
JavaScript version, then I have seen code suggested that allows you to set a
global variable based on the version that the browser knows it is.
** JS 6-8 - shows the suggested code for this technique
In MSIE 5.5 and NN 4.79, this seems to work but...
** JS 6-9 - shows that this method may not be as reliable as it is purported
to be.
Here I added the 1.8 and 2.0 code to illustrate that I don't think this works
very well. Since neither implements 1.8 nor 2.0, these values should not be set
- but they are.
The point? Test test test. It can be impossible to have multiple versions of
MSIE, because of the way this browser works, but you can get multiple versions
of NN and Opera - go to browsers.evolt.org to get installs of older browsers.
Don't forget Macintosh users!
The noscript tag
----------------
The noscript tags allow you to add code that is supposed to display in browsers
that do not have scripting at all. This works if your browser does not know
about the script tags and you place the HTML comments in the code as we normally
have been doing. The problem is that these tags were introduced with Navigator
3 and MSIE 4, so the data in the noscript tags might display even if scripting
is used.
One final topic
---------------
Suppressing multiple submits - this can be a problem if you have mouse-happy
users. You may have seen messages like "please only click submit once to avoid
being billed multiple times..." Here is a small bit of JS to prevent that from
happening yourself:
var alreadySubmitted = 0;
function validateForm()
{
if (alreadySubmitted == 1) {
alert("You have already submitted.");
return false;
}
// validate
alreadySubmitted = 1;
return false; // or true, if really submitting
}
** JS 6-10 - illustration
See the last link for links to more browser detection scripts and to the Evolt
site.