Best Practices | Knowledge Management | Security | Tutorials | Books | Tools

Intranet Journal

Home | Exchange | FAQ | Software & Standards

Cross-Platform Compromises
(last)

Alternatively, you can do the same branching strictly via client-side scripting. Depending on the amount of granularity you wish to establish for different browser brands and versions at your site, you have many branching techniques to choose from. All these techniques are based on a predominantly blank page that has some scripted intelligence behind it to automatically handle JavaScript-enabled browsers. Any script-enabled browser can execute a script that looks into the visitor's browser version and loads the appropriate starter page for that user. Example 2-1 shows one example of how such a page accommodates both scripted and unscripted browsers.

Example 2-1: Branching Index Page

  <HTML> 
  <HEAD> 
  <TITLE>MegaCorp On The Web</TITLE> 
  <SCRIPT LANGUAGE="JavaScript"> 
  <!-- 
  if (parseInt(navigator.appVersion) >= 4) {
    if (navigator.appName == "Netscape") {
        window.location.href = "startNavDHTML.html"
    } 
    else 
    if (navigator.appName.indexOf(
               "Internet Explorer")!=-1) {
        window.location.href = "startIEDHTML.html"
    } else {
        window.location.href = "startPlainScripted.html" 
    }
  } else {
      window.location.href = "startPlainScripted.html" 
  }
  //-->
  </SCRIPT> 
  <META HTTP-EQUIV="REFRESH" CONTENT="1;
     URL=http://www.megacorp.com/startUnscripted.html"> 
  </HEAD>

  <BODY> 
  <CENTER> 
    <A HREF="startUnscripted.html">
    <IMG SRC="images/megaCorpLogo.gif" HEIGHT=60 
     WIDTH=120 BORDER=0 ALT="MegaCorp Home Page"></A> 
  </CENTER>
  </BODY> 
  </HTML>
The script portion of Example 2-1 provides three possible branches, depending on the browser level. If the browser version is 4 or later, this index page automatically loads a Navigator-specific starter page for Netscape Navigator users, an IE-specific starter page for IE users, or a starter page that accommodates the outside chance of there being a Version 4 browser of yet another brand. That same plain scripted starter page is the one that all other JavaScript-enabled browsers load.

For browsers that either don't have JavaScript built in or have JavaScript turned off, a <META> tag refreshes this page after one second by loading a starter page for unscripted browsers. For "bare bones" browsers that may not recognize scripting or <META> tags (including Lynx and browsers built into a lot of handheld devices), a simple image link leads to the unscripted starter page. Users of these browsers will have to "click" on this link to enter the content portion of the web site.

Example 2-1 is an extreme example. It assumes that the application has as many as four different paths for four different classes of visitor. This may seem like a good idea at first, but it seriously complicates the maintenance chores for the application in the future. At best, it provides a way to filter access between DHTML-capable browsers and all the rest.

Internal Branching

Instead of creating separate documents for Navigator and IE 4 users, you can use JavaScript to write browser-specific content for a page within a single document. For example, you may find that some style sheet specifications are not rendered the same in both browsers. To get the same look for an element, you can create a browser-specific branch to use the JavaScript document.write() method to generate content suited to each browser. Example 2-2 show a simplified page that writes HTML for a positionable element two different ways. For Internet Explorer, the HTML is a DIV container; for Navigator, it is a <LAYER> tag that loads an external file (whose content is not shown in the example).

Example 2-2: Internal Branching for Browsers

<HTML> 
<HEAD> 
<TITLE>MegaCorp On The Web</TITLE> 
<SCRIPT LANGUAGE="JavaScript"> 
<!-- 
var isNav4, isIE4
if (parseInt(navigator.appVersion) >= 4) {
    isNav4 = (navigator.appName == "Netscape")
    isIE4 = (navigator.appName.indexOf(
            "Microsoft") != -1)
}
//-->
</SCRIPT> 
</HEAD>

<BODY>
Some regular text
<SCRIPT LANGUAGE="JavaScript">
<!--
var output = ""
if (isIE4) {
    output += "<DIV ID='help' "
    output += "STYLE='position:absolute; top:75; 
               width:350; border:none; "
    output += "background-color:#98FB98;'>"
    output += "<P STYLE='margin-top:5; align:center'>
               <B>Instructions</B></P>"
    output += "<HR><OL STYLE='margin-right:20'>"
    output += "<LI>Step 1."
    output += "<LI>Step 2."
    output += "<LI>Step 3."
    output += "</OL><DIV align='center'><BUTTON "
    output += "onClick=
      'document.all.help.style.visibility=\"hidden\" '>"
    output += "Click Here</BUTTON></DIV></DIV>"
} else if (isNav4) {
    output += "<LAYER ID='help' TOP=75 WIDTH=350 
                SRC='help.html'></LAYER>"
}
document.write(output)
//-->
</SCRIPT>
</BODY> 
</HTML>
The key to efficient branching in such a page is establishing a Boolean global variable for each browser at the top of the document (isNav4 and isIE4 in Example 2-2). This allows scripts elsewhere in the document to make decisions based on the browser that is running the script and writing the HTML that applies to that browser. Notice in Example 2-2 that the if construction writes HTML content only if one of the two global variables is true. Conceivably, a user who does not have a DHTML-capable browser could gain access to the URL of this page. In this example, the only content such a user would see is the short line of text after the <BODY> tag.

Designing for the Common Denominator

From a maintenance point of view, the ideal DHTML page is one that uses a common denominator of syntax that both browsers interpret and render identically. You can achieve some success with this approach, but you must be very careful in selecting standards-based syntax (e.g., CSS1 and CSS-P) that is implemented identically in both browsers. Because some of these standards were little more than working drafts as the browsers were released to the world, the implementations are not consistent across the board.

DHTML feature sets that you can use as starting points for a common denominator approach are the standards for Cascading Style Sheets Level 1 and CSS-Positioning. When you peruse the documentation from the browser vendors in this arena, it is nigh impossible to distinguish support for the recommended standard from a company's proprietary extension that adheres to the spirit, but not the letter, of the standard. Just because a feature is designated as being "compatible with CSS" does not mean that it is actually in the published recommendation. Refer to the reference chapters in Part II of this book for accurate information on the implementations in the browsers as it relates to the standards.

You are likely to encounter situations in which the same style sheet syntax is interpreted or rendered slightly differently in each browser. This is one reason why it is vital to test even recommended standards on both browser platforms. When an incompatibility occurs, there is probably a platform-specific solution that makes the result look and behave the same in both browsers. To achieve this parity, you'll need to use internal branching for part of the page's content. This is still a more maintainable solution than creating an entirely separate page for each browser.

Some features that are available in one browser cannot be translated into the other browser. Internet Explorer 4 includes a few DHTML capabilities that have no parallel features in Navigator 4. Therefore, don't expect to find common denominators for dynamic content (beyond swapping images of the same size), transitions, or filters. DHTML facilities in Navigator 4 can be re-created in IE 4 either directly or via internal branching. For example, the IE 4 <IFRAME> element closely resembles the Navigator 4 <ILAYER> element.

If this short lesson in finding a common denominator of functionality reveals anything about the Version 4 browsers, it is that if you start your design with Navigator 4 in mind, you can probably develop an IE 4 version using some or all of the techniques described in this chapter. But if you start with IE 4 and get carried away with its DHTML features, you may be disappointed when you run your application in Navigator 4.

Custom APIs

Despite the common denominator of CSS1 and CSS-P recommendations for the HTML elements in documents, scripted access to these objects and their properties can vary substantially from one browser to the other. Even when the two browsers have similar objects with similar properties, the syntax for the property names may be different enough that you need to use internal branching for your application to work seamlessly across platforms.

Once you go to the trouble of writing scripts that perform internal branching, you might prefer to avoid doing it again for the next document. Both browsers allow JavaScript to load libraries of script functions (files named with the .js extension) that you can link into any HTML document you like. You can therefore create your own meta language for scripted DHTML operations by writing a set of functions whose terminology you design. Place the functions in a library file and rely on them as if they were part of your scripting vocabulary. The language and function set you create is called an application programming interface-an API. Example 2-3 shows a small portion of a sample DHTML API library.

Example 2-3: Portion of a DHTML Library

// Global variables
var isNav4, isIE4
var range = ""
var styleObj = ""
if (parseInt(navigator.appVersion) >= 4) {
    if (navigator.appName.indexOf(
        "Microsoft") != -1) {
        isNav4 = true
    } else {
        isIE4 = true
        range = "all."
        styleObj = ".style"
    }
}

// Convert object name string or object reference
// into a valid object reference
function getObject(obj) {
    var theObj
    if (typeof obj == "string") {
        theObj = eval("document." + 
                 range + obj + styleObj)
    } else {
        theObj = obj
    }
    return theObj
}

// Positioning an object at a 
// specific pixel coordinate
function shiftTo(obj, x, y) {
    var theObj = getObject(obj)
    if (isNav4) {
        theObj.moveTo(x,y)
    } else {
        theObj.pixelLeft = x
        theObj.pixelTop = y
    }
}
One of the incompatibilities between positionable elements in Navigator 4 and IE 4 is the format of references to the element's properties and methods. For an unnested Navigator layer object (remember that all positionable items in Navigator are treated as layer objects), a reference must begin with the document object reference (e.g., document.layerName). In contrast, properties that govern IE 4 positionable elements are properties of a style property associated with the object. Moreover, every named object, no matter how deeply nested within other containers, can be referenced from the document object if the all keyword is included in the reference (e.g., document.all.objectName.style).

The getObject() function of Example 2-3 is an all-purpose function that returns a reference to an object that is passed originally as either a string that contains the object name or a ready-to-go object reference. When the incoming object name is passed as a string, the eval() function assembles a valid reference based on the browser running the script. If the browser is Navigator 4, the range and styleObj variables are empty strings, and the resulting reference being evaluated is "document.objectName"; in IE 4, the keywords all and style are assembled as part of the reference. For both browsers, when the incoming parameter is already an object reference, it is passed straight through: the assumption is that the object reference is valid for the current browser (probably based on internal branching in the main document that calls this function).

The more interesting function in Example 2-3 is shiftTo(), which changes the position of an object, so that it is located at the specific coordinates that are passed as parameters. Each browser has its own way to set the position of an object in a script. Navigator 4 features a one-step moveTo() method of a layer object; IE 4 requires setting the pixelLeft and pixelTop properties of the object's style property. Those differences, however, are handled by the function. Any time you need scripted control of the movement of an item in a document, you can call the shiftTo() function to do the job in whatever browser is currently running.

Building an API along these lines lets you raise the common denominator of DHTML functionality for your applications. You free yourself from limits that would be imposed by adhering to 100% syntactical compatibility. [In Chapter 4 of Dynamic HTML: The Definitive Reference, Goodman presents a custom API that smooths over potentially crushing CSS-Positioning incompatibilities. -Ed.]

Cross-Platform Expectations

Before undertaking cross-platform DHTML development, be sure you understand that the features you can exploit in both browsers - regardless of the techniques you use - are limited to comparable feature sets within the realms of style sheets, positionable elements, event models, object models, and downloadable fonts.

Dynamic content on a small scale is also a cross-platform possibility, but the instantaneous reflowing of modified content, display filters, and transitions that are available in Internet Explorer 4 have no parallels in Navigator 4.

 
From a maintenance point of view, the ideal DHTML page is one that uses a common denominator of syntax that both browsers interpret and render identically.
 
Internet Explorer 4 includes a few DHTML capabilities that have no parallel features in Navigator 4. Therefore, don't expect to find common denominators for dynamic content (beyond swapping images of the same size), transitions, or filters.
 
The Author
Danny Goodman has been an active participant on the editorial side of the personal computer and consumer electronics revolutions since the late 1970s. His articles in the field have appeared in some of the most prestigious general audience publications and he has written dozens of feature articles for leading computer publications, such as PC Magazine, PC World, Macworld, and MacUser. Danny is currently a monthly columnist for Netscape Communication's online developer newsletter, View Source. He is also the author of more than two dozen books on computing and information superhighway technologies, including the popular JavaScript Bible.

Copyright 2002 Jupitermedia Corporation, All Rights Reserved.
Legal Notices | Licensing, Reprints, & Permissions | Privacy Policy | Advertising on Intranet Journal
Home | eXchange | F A Q | Find | Register |