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...
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.
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.forms
document.images
etc),
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"
.
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]
.
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 omnipresentwindow
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:
function myFunction(e) { // let's not forget poor Explorer // which doesn't pass the event as a parameter if(!e) e=window.event; // rest of the code // ... }
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? =)
The previous section covered the mechanisms necessary to get the object which represents an event. But the issue does not finish there, since the properties defined in Explorer are not the same ones that the properties that the standard dictates (i.e. those that Firefox implements).
In Explorer | Description | In Firefox (DOM standard) |
---|---|---|
srcElement | The element which fired the event. | target , but in Firefox the nodes of type text can also fire
events, so to keep things working you'll need to climb up the tree until you
find a element's (tag's) node:
var node = e.target; while(node.nodeType != node.ELEMENT_NODE) node = node.parentNode; |
fromElement | The element in which the mouse was before. | 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
continuing propagating upwards in the DOM tree.
| The stopPropagation() method of
the event should be called.
|
returnValue | Assigning false to this property is requesting to Explorer not to execute the event's default action (like following 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.
|
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.
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.
|
element.attachEvent( event_name, function)
| Attachs function to element's event_name. |
element.addEventListener(event_name, function, false) ,
but see above.
|
contains(node)
| This method is available in every element, and allows to ask if another node is a descendant of this one. |
DOM level 2 does not have an equivalent method, but a very simple method like the shown below can be used (it works in Firefox and Explorer): // Finds out if a is an ancestor of b function contains(a, b) { // we climb through b parents // till we find a while(b && (a!=b) && (b!=null)) b = b.parentNode; return a == b; } The new DOM level 3 standard defines
|
document.parentWindow
| It obtains the window in which the document is. |
document.defaultView .
Note that the window
object is available everywhere. This property could make some sense
in frame-using pages, but I don't think the lack of it
would render anything imposible.
|
myForm
|
Access a form defined by
<form name="myForm">
|
You may use document.myForm , it
works everywhere.
|
element.innerText
| Replaces element's content with the specified plain text. | In Firefox, this property is called textContent. It's part of the DOM Level 3 standard. |
children
| Array of child element nodes. |
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.
The sad part is that Explorer does not support childNodes. Since Firefox 3.5 there's support for IE style children property, but it remains nonstandard |
element.designMode
|
element.designMode too, but with
many differences.
| 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. |
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.
The code which can easily be replaced is:
In Explorer | In Firefox | Notes |
---|---|---|
new ActiveXObject("Microsoft.XMLHTTP")
|
new XMLHttpRequest()
| It's also supported in the new Explorer 7. You may also check Apple's documentation. |
new ActiveXObject("Microsoft.XMLDOM")
|
document.implementation.createDocument(ns, root-element, null)
| The API is slightly different. |
Also visit my introductory article about XML.
My curriculum vitae.