Standards, standards, standards
To name a few: events are handled differently, as are call back functions, access to style properties... the list goes on.
At first, developers tried to determine the browser in question using the browser details in the navigator object.
var browser = navigator.userAgent;
var isIE = browser.match(/MSIE/);
The problem with this "browser sniffing" is that the connection between the browser type and behavior is arbirary and tenuous. It's the CSS hacking problem all over again.
Feature sniffing - from each according to his ability
Nowadays, developers opt for "feature sniffing."
Here, the code tests for the availabilty of a specific feature, rather than browser. If the browser supports the feature, use it. If not, use a different feature. Keep going till you're out of options, in which case you "exit gracefully."
Even if a browser manufacturer decides to remove old features and add new, your code stays the same.
For example, to get an object reference to an element, try:
var myId = "myId";
if(document.getElementById) myObj = document.getElementById(myId);
else if(document.all) myObj = document.all[myId];
By testing whether the method name is null - document.getElementById without the () - we discover whether or not it is available to us.
The place to test, obviously, is at the start of a code unit that will require the features, such as at the initialization of an object that uses the feature later on.
Mike Foster has done us all a favor by creating a library of useful functions that take browser inconsistencies into account.
For example, to obtain an object reference to an HTML element:
var elem = xGetElementByID("myId");