Making your web page compatible with Firefox

The following is a list of things to review so that a web page is
compatible, not only with Firefox, but with any browser which implements the
latest standards, including of course Mozilla derivates as Camino, Galeon,
Epiphany, etc.

Some might say that making a page compatible requires double the effort
in making it, and that is not worth the trouble since everybody uses explorer.
In this article I want to show that this is not true. It's
roughly the same effort to make a page that is compatible with Firefox as
one that that is not.

This text does not intend to tell you how to
make pages compatible with ancient browsers (as Netscape 4 or Explorer 4)
That would certainly be a much larger task.
This article aims to guide you about supporting browsers that are very similar in
their support of things like dynamic HTML.
It's not necessary to have a page for each kind of browser, it's
better to share the code while taking into account the small differences. The
details enumerated here will be used for browsers like
Firefox,
Mozilla,
Netscape 6+, Konqueror, Opera,
Apple's Safari,
etc.. Some
of the properties explained which are equivalent to those of Explorer don't
belong to any standard, these cases will be noted.

Sripting. The great majority of the compatibility problems falls in this
category, specially in "AJAX" applications. And they are not generally
problems with the JavaScript language itself, but with the fact that the
browsers represents the page in objects differently. A different
API, sortof. This API is called the DOM (although in Microsoft
docs you should search for DHTML instead).

Let's now see which are the most common problems...

Detections

A common way of coping with different browser versions is to
detect the one which is being used. This is
generally a bad idea. It's much more advisable, maintainable and
easy just to detect each desired feature
when you make use of it. That way you will automatically support all
browsers which implement that feature, and will narrow the posibility
of leaving a browser unsupported. JavaScript is a very dynamic language that
allows one to ask if an object has certain method or property, so it's
simple to detect things correctly. In order to verify the existence of a
method or property in an object simply put the expression in a boolean context.
For example, to
ask if the property prop exists in the object
o one can write: if(o.prop) {.

Another common error
is to check if the browser has something, and if it doesn't to
assume that it has another thing. The typical case involves
document.layers (the obsolete and frightful layers API
included in Netscape 4). Some badly coded
pages assume that if a browser does not have document.all it's
safe to assume that it supports the other interface. This cannot be relied
upon. It's better to directly test what one is going to use.

Locating objects

Explorer 4 introduced the ability to dynamically modify the underlying
page structure, and some people called that dynamic HTML. The page structure
modifications are done from JavaScript code. As in the browser's JavaScript API there were
already many things hanging from document (such as
document.formsdocument.imagesetc),
someone at Microsoft said:

― Where do we put ALL of the others?

― I've got it!: In document.all

Later, the W3C created a function for
that: document.getElementById(id). It's supported
in Explorer from release 5. What do we do with IE4 users? You should not
care! Nobody uses it anymore, as Explorer 5 or better have been forced to
Windows users since Windows 98 "Second Edition". Current numbers for IE4 are
below %0.1.

Now the thing is just to replace in all places this way: Where you see
document.all.theMenu.style.color="black" change it to
document.getElementById("theMenu").style.color="black".

Parentheses or brackets

In the JavaScript representation of a web page there are several arrays.
And arrays are meant to be accessed with [].
Microsoft has the concept of collections in his scripting languages,
which is a variation of the same subject, but these collections are accessed with
(). They had the terrible idea to transfer this to its
implementation of JavaScript, thus document.forms(0) works
in Explorer, but in no other browser. One must always use [], i.e.:
documents.forms[0].field.value and
document.images[0].

Events

Accessing the event object

At first, handling an event was just to put just a little bit of code in
an onclick attribute somewhere. Netscape extended this so that
one could within that small piece of code, access an event
variable. In that variable one could find out most interesting details as
what key would have been pressed and other things.

When Microsoft entered the scene they thought:

― In which object should this event variable be so
that it's available in the code snippet?

― Let's put it in window, as everything which is in
the omnipresent window object is always in scope.

And thus the ugly window.event was born, which would come to
be some kind of global variable.

This window.event, in addition to being a terrible idea, is
not part of any standard (luckily). Therefore the only safe place from
which it's safe to access a variable named "event" is from the
onevent attribute (e.g.: onMouseOver="..."). In that
place there's a variable named event. If a function is called,
event should be passed as a parameter. Example: <a
onmouseover="mouseOver(event) "...

A somewhat more advanced use of the events consists of assigning
functions to certain properties in the objects you'd like to monitor, e.g.:
findObject("myLink").onmouseover=myFunction;. In this
case the mechanism explained in the previous paragraph is not applied. In
their place, the the
DOM event standards compatible browsers
will pass the event as a parameter to the myFunction function,
which could be defined the following way:

In Explorer, registering for events can be done by using
the attachEvent function. In Firefox, the same thing is
accomplished with addEventListener (it takes an extra boolean
parameter, just put false there). Note that event names in the
DOM standard don't begin with "on", so you will need to remove that. BTW,
why don't you just assign the function to the proper
element.onevent property? =)

target if the event is onmouseout,
relatedTarget if the event is to onmouseover.

toElement

The element to which the mouse was moved.

relatedTarget if the event is onmouseout,
target if the event is onmouseover.

cancelBubble

Assigning true to this property prevents the event from
con­tinuing propa­gat­ing upwards in the DOM tree.

The stopPropagation() method of
the event should be called.

returnValue

Assigning false to this property
is re­quest­ing to Explorer not to execute the event's default action
(like fol­low­ing a link).

The preventDefault() method should be
called.

offsetX, offsetY

Position of the event with respect to the element that generates it.

If the mouse is on a absolutely, fixed or relatively
positioned element, then you can use layerX,
layerY (non-standard). However,
event.target is in a normally (static)
positioned element these properties will give you the offset
with respect to the document root element
(which normally corresponds to the page). In this case your
only option is to manually calculate the "offsetX" value by
traversing all the hierarchy from the document root element,
adding the objects' offsetLeft / offsetTop values.

Assorted differences in the DOM tree

By DOM tree I mean the hierarchic structure of objects that the browser
uses to represent the tags that make up the page. There are small
differences that can affect the compatibility of a page.

Differences in several properties and methods

In Explorer

Description

In Firefox

window.screenLeft,
window.screenTop

Position of the window browser relative to the screen.

window.screenX - someValue, window.screenY + someValue
These properties are not extactly the same as the Explorer
ones. In explorer they give the coordinates of the origin of
the IE control, while in Firefox they give the origin of
the Firefox window itself.

The DOM doesn't define such a thing. But it defines that each node has
a childNodes property which is very
similar. The big difference is that childNodes
also includes text nodes. So, if you have code which does
children[n], then you'll have to
replace it with
childNodes[n+Z], where
Z is the number of (previously ignored) text
nodes which are before the wanted element.

Mozilla has implemented support for having editable content
(it's called "Midas" in Mozilla), but it has a slightly
changed API. They have documented converting this to Firefox.

ActiveX

No way. No other browser supports ActiveX. But you still may be lucky:
Some of the features which are available through ActiveX can be accessed in
Firefox without it! If you are using a custom component, there you are out
of luck.