Using Old Page layout tricks with new technology

Originally published at Netscape Enterprise Developer, now archived at the Wayback Machine

Prior to the release of Netscape Navigator 4.0 and Microsoft Internet Explorer 4.0, Web developers had to use a lot of tricks to control the layout and looks of a Web page. There was no easy way to control the positioning of elements on the page — the two photos that lined up perfectly over the text on your browser when you laid out your page could be completely askew when someone else downloaded them.

To counteract this non-standard display problem, Web authors tended to develop an arsenal of “tricks” that made layout easier. Among the more common tricks were the use of HTML tables to control page layout and a one-pixel transparent GIF to control the placement of content within a line or within a page.

With the newer 4.0 browsers, however, site developers have new, fewer roundabout techniques to control element placement and page layout. For instance, the Cascading Style Sheet Positioning (CSS-P) specification (now incorporated into the CSS2 working effort) and the original CSS1 specification add layout capabilities to HTML development. (See the page listed in our Resources section below for detailed Cascading Style Sheet information.) In addition, the rise of dynamic HTML technology means that authors not only have control of the static placement of HTML elements on a page, they can also move elements and hide or show them after a page is displayed.

Even with these new techniques, however, I find myself using old standbys — specifically, HTML tables and the one-pixel transparent GIF — but now I’m using them in combination with the new technologies to create interesting and useful effects. You too can combine the best of the old and new for more control over your page layout.

The one-pixel transparent GIF
Prior to the release of Navigator 4.0 and IE 4.0 and the development of the Cascading Style Sheet Positioning spec, Web page authors were severely limited in how much we could control the placement of Web page elements. One element that you could use to provide some placement control was the image element, defined with the <IMG> tag. Using the image element, an author could specify a vspace or hspace (vertical or horizontal spacing) value, as well as a vertical or horizontal alignment (right or left, top or bottom).

In addition to the image element, some older browsers supported the use of the transparent GIF. Using a transparent GIF, the specific color you identify within the image is transparent when loaded into a browser.

David Seigal of Killer Web Site fame combined the two ideas and came up with the image element that happened to be a small one-pixel transparent GIF. Since it’s tiny and transparent, it can be easily added to a layout without disrupting the underlying content; by using the specific spacing value capability of the image element on the one-pixel transparent GIF, you could add white space or position content in a specific location.

Beginning with Navigator 4.0 and followed by Internet Explorer 4.0, however, Web authors began using CSS-P for specific element positioning and CSS1 for adding margins or padding to a page (or even within an element). There was no longer a need for the little one-pixel transparent GIF. But an odd thing happened when I was about ready to delete my trusty little GIF file: I actually found a new use for it.

I wanted to create a page for my Dynamic Earth Web site that showed several different minerals and included a moveable “frame” that positioned itself over each image based on some event. When the frame was over the image, the image was activated — if the user clicked on it, information about the mineral would appear. Of course I knew I could use CSS1 to create a frame around content, then use CSS-P to move the frame, but I wanted the interior of the frame to be transparent.

The solution I came up with was to create the frame using a one-pixel transparent GIF for the interior, setting its width and height to be the exact size of the frame I wanted. Using CSS-P, I could then move this GIF around from image to image. I also created two separate layers for each image: one that had the original image, which didn’t do anything when the reader clicked it, and another that had a framed, transparent GIF, which showed the mineral information layer when clicked. Figure 1 shows a snapshot of this page:

 


Figure 1

The one-pixel transparent GIF turned out to be much more than a simple placement and whitespace tool; it’s a handy tool that can be stretched and shrunk as needed and reused as often as necessary.

Positioning a menu for both old browsers and new
I soon found other uses for my newly rediscovered little GIF file, including a solution for a new Web page authoring problem I encountered.

I used to have a menu along the top of my pages that contained four separate images and text-based links just below the images. I used an HTML table to control the placement of images and text, ensuring that the images were placed directly next to each other and were aligned along the top of the page. One thing I never liked about this approach was that I preferred that menu text be layered over the images rather than displayed below them.

With CSS-P, I could position the images at the top of the page and use absolute positioning to place the menu text over the images. The problem I encountered, though, is that the page didn’t look very good when viewed with a pre-Navigator or IE 4.0 browser.

Instead, I used an HTML table along the top of the page, including the four images and their associated text in the table cells. However, I included these images and text in blocks delimited by <DIV> tags (these allow formatting to span multiple elements) and then used CSS-P to position the images and text so they overlapped. With this approach, older browsers see the page as they always have, as shown in Figure 2, but in the newer browsers the page has the new overlapped look, as shown in Figure 3.

 


Figure 2

 


Figure 3

There was one last problem with this approach, though. The thing with absolute positioning is that if you have it on content within a table element, the contents do not influence the table row’s height or the table cell’s width. This means that any other content on the page gets placed after the table, but overlaps the images and text because the table is not sized correctly.

I found that a simple solution for this was to use my trusty one-pixel transparent GIF as the first table cell and set it to the height I wanted the table to occupy. This sized the entire row to the height I needed to cover the positioned content — once again, a successful blend of the old and new.

XML Expectations

Originally published at Netscape Enterprise Developer, now archived at Wayback Machine

Extensible Markup Language is a language that defines other languages. It also has the potential to give structure and meaning to the information contained in HTML documents or any other data form — making such information naturally as searchable and structured as the information locked into a database. Such capabilities mean that XML can turn our current view of data upside down — instead of a static, impenetrable lump of information, a file that uses XML suddenly has a logical structure that can be manipulated, queried, and changed without delving down into the data itself. The potential of such a meta-language is huge — if it’s implemented as an open standard. Right now, XML remains such a standard, and if it continues to evolve along open lines, it could drastically improve Web-based development.XML is similar to SQL in a number of ways; SQL is also an example of a multi-purpose language used to define data structures and query those same data structures without concern as to how the information is displayed or used. The only guarantees are that the information is defined in structures, the structures follow certain rules, and the information contained within the structures can be accessed automatically or manually. Both SQL and XML define structures for information in the form of elements, element attributes, and element content. The main difference is that instead of defining data that is stored in a physical storage medium usually only accessible by a database engine, XML describes data that is stored and accessed from within documents.

XML’s parent: SGML
XML is a subset of SGML (Standardized General Markup Language), a generalized markup language that was passed as an ISO standard in the 1980s. Rather than specifying a language’s elements directly, SGML is used to define the rules that constrain the elements of a specific language.

SGML grew out of the need to define a document’s structure and to define rules used to determine whether the document is valid and well formed. The document’s structure is defined through the use of markup tags, which delimit the elements, and Document Type Definition (DTD) files that define each element’s structure and content, providing a sort of grammar for the document.

For example, using SGML, a customer element within a document could have the following structure:

<CUSTOMER name="Shelley Powers" id="CUST011A1">
<PO id="PO23349008">
<POITEM id="POI1">
<ITEM id="14453">
Item ID: 14453
Item Desc: some description
</ITEM>
</POITEM>
</PO>
</CUSTOMER>

To validate the markups used to define the structure of the document, an associated DTD would have to be created, with statements similar to the following:

<!ELEMENT customer - - (POITEM)+><!ATTLIST customer    name CDATA   id CDATA>

This extremely simplified and abbreviated DTD uses an Extended Backus-Naur Form (EBNF) syntactic notation to create the grammar.

Using a standardized meta-language to define entities within a document allows SGML parsers to pull out the individual entities (such as the customer entity just described) and any associated attributes and content. An application can then use that information for a number of purposes, including the following possibilities:

  • To define information in a database-neutral format for transport between unlike databases.
  • To provide a search engine that allows a person to query on the entity type as well as the data.
  • For report generation, or even an online hypertext order processing form that allows the reader to drill down within the document to find the desired information.
  • To define a standard language for a specific industry or science, such as the petroleum industry or chemistry, which includes special notational conventions.

The concept of SGML is very attractive: Define a language that in turn defines a document structure used for a specific group of documents and which can be extended without impacting the underlying language generation mechanism. Unfortunately, the downside to SGML is that it is far from trivial to define the DTD for a language. SGML is a complex standard that is difficult to implement.

HTML, a derivative of SGML
SGML did, however, provide the roots of the first Web document specification, HTML. HTML was derived from SGML, except that it predefined a group of elements that controlled the delivery of a Web page’s content. In addition, the original HTML elements were expanded to include suggested presentation elements that controlled the appearance of the Web page. SGML does not control the presentation of elements, only the element structure and semantics.

The following code defines an HTML unnumbered list element, which is defined by the DTD associated with the HTML 4.0 specification as having a start and end tag and containing at least one list item:

<!ELEMENT UL - - (LI)+>

According to the EBNF associated with SGML, this DTD states that UL is an element, the double dashes assert that the element requires a start and end tag, and the element consists of at least one, and possibly more than one, list item (LI). When a user agent such as a browser parses an HTML element, it knows to look for both beginning and ending UL tags and at least one LI element contained within those tags.

Associated with the DTD for HTML 4.0 is an implied visual presentation of an unnumbered list, which is that each list item has a specified list graphic, each list item is on a separate line, and each list item lines up beneath the previous list item. However, not all user agents (such as browsers) are visual, so presentation can only be a suggestion, not a mandate.

After the first releases of the HTML specification, new elements crept into the language to provide control over page presentation. One such element is the FONT element, which controls the size, color, type, and font family of any text the element contains. The problem with using a specific tag like FONT, however, is that non-standardized tags can lead to different Web page presentations depending on the user agents.

To help differentiate an element’s structure and its presentation in HTML, the W3C issued a recommendation for CSS1, or Cascading Style Sheet Level 1, a specification that provides presentation information for HTML elements.

The real advantage of HTML was that it was relatively easy to code and display, even in different browsers. The ease of HTML was directly responsible for the massive growth of the Web. If Web document access had begun with XML, chances are you wouldn’t be reading this article right now and Web access would probably be limited to the scientific community. We initially needed a simple mechanism to create Web documents, and HTML was it. The very lack of flexibility was the language’s strength.

Now that the Web and Internet-based technologies have matured to a certain extent, enterprise developers are increasingly demanding a way to build flexibility into documents like Web pages in order to increase their effectiveness and ease of access.

Enter XML
XML arose from a need to create more generalized markup languages without having to follow the large and complex SGML standard. The XML standard still demands that a markup language be defined as well-formed, but it makes the validation step optional, which means that an associated DTD is not required (though one can be included). Additionally, XML uses only a subset of the rules for SGML, letting developers understand the principles and implementation of the technology more quickly.

Like SGML, XML is a meta-language that provides rules to define a set of tags that can be used within a document. These tags are then used to delimit an XML entity, its attributes, and its contents, and to define the elements’ syntax. These tags are read by a XML processor, which in turn provides an application with access to the entities. The application can then perform one or more actions on the XML entities.

XML processors can either be validating, which means that they make use of an associated DTD in order to ensure valid structures, or non-validating. Regardless of whether or not they are validated, XML documents can be considered to be well-formed as long as they match the XML syntax overall and as long as each entity within the document meets the syntax for a well-formed XML entity.

The main requirements for a well-formed Extensible Markup Language include the following:

  • The language may begin with a valid XML declarative statement or prolog.
  • There is one element that acts as the root element and which acts as parent to all other elements.
  • Elements are either not empty or, if they are empty, they have a “hint” encoded within the element that defines this information to the XML parser.
  • Non-empty elements must have start and ending tags.
  • All elements except the root element are contained within some element, referred to as the element’s parent; all contained elements are referred to as the parent element’s children.
  • Elements can contain character data, other elements, CData sections, processing instructions or comments.
  • Each parsed element within the document is well-formed.
  • Character data that may be processed as XML is enclosed within CData sections.
  • Documents can include comments, white space, and processing instructions.

Consider that a valid and well-formed XML document consists of the following EBNF format non-terminating symbols (non-terminating meaning that the symbols are themselves expanded elsewhere):

document::= prolog element Misc*

A complying document could be as simple as:

<?XML VERSION="1.0" ENCODING="UTF-8"?>
<ARTICLE name="XML" author="Shelley Powers"/>

This document consists of the prolog section which includes the XML declaration (“<?XML”) and includes the version number of the XML definition, as well as the encoding declaration. It also contains one element, ARTICLE, which has two attributes, NAME and AUTHOR. Since the element is an empty element, it ends with a backslash to signal to the processor that the element contains no other content. This is necessary for a non-DTD (non-validating) document. Otherwise the XML processor would not know when to look ahead in the parsing for required element content. This is one of the key features of XML: Forward processing information is embedded directly within the document, negating the necessity of creating an associated DTD.

The example just provided is a well-formed document, but not a valid one, since no DTD is provided for validation. The example also demonstrates the simplicity of XML. An even simpler version of the language would be:

<ARTICLE name="XML" author="Shelley Powers"/>

To make the document a valid one, I could have added a DTD for the ARTICLE element directly into the document, or linked to a DTD external file:

<?XML VERSION="1.0" ENCODING="UTF-8"?>
<!DOCTYPE article SYSTEM "article.dtd">

<ARTICLE name="XML" author="Shelley Powers"/>

XML in action
Though the standard is relatively new, there are several XML parsers that validate whether an XML document and its associated DTD fit the rules for a valid XML document. In addition, these same parsers may return the elements within a document exposed in their tree-like form — a form that can be used by applications.

XML is being used in the real world already. For example, Microsoft has defined an XML application it terms “Channel Definition Format,” or CDF. CDF files contain entities that describe the contents of an active channel. Following the accepted technique for XML, CDF files do not contain reference to a DTD file and instead use clues embedded within the tags and tag definitions to provide forward-looking information for the XML parser.

CDF’s purpose is to provide a document that defines the use of push technology at a specific Web site, including which pages are to be displayed as channels, what icons to display, what the update schedules are, etc. With this information, the XML processor provides the key elements that a channels-based application can use to control channel access on the Web site.

The following code shows the CDF file I have defined for use at my personal Web site. The root element for the file is the CHANNEL element. It is the parent element for several other elements, such as an ICON element, an ITEM element, and an ABSTRACT element. Each of the elements within the document may or may not have attributes, and a child element may in turn be the parent for another element:

<?XML VERSION="1.0" ENCODING="UTF-8"?>
<CHANNEL HREF="http://www.yasd.com/plus/index.htm" 
        BASE="http://www.yasd.com/plus/">
    <TITLE>YASD+</TITLE>
    <ABSTRACT>YASD+ pages, using the newest technologies</ABSTRACT>
    <LOGO HREF="http://www.yasd.com/mm/wide_logo.gif" STYLE="IMAGE-WIDE"/>
    <LOGO HREF="http://www.yasd.com/mm/logo.gif" STYLE="IMAGE"/>
    <LOGO HREF="http://www.yasd.com/mm/icon.gif" STYLE="ICON"/>
    <SCHEDULE>
        <INTERVALTIME DAY="1"/>
        <EARLIESTTIME HOUR="0"/>
        <LATESTTIME HOUR="12"/>
    </SCHEDULE>
    <ITEM HREF="http://www.yasd.com/samples/bytes/daily.htm">
        <LOGO HREF="http://www.yasd.com/mm/icon.gif" STYLE="ICON"/>
        <ABSTRACT>YASD Code Byte</ABSTRACT>
    </ITEM>
    <ITEM HREF="http://www.yasd.com/samples/bytes/cheap.htm">
        <LOGO HREF="http://www.yasd.com/mm/icon.gif" STYLE="ICON"/>
        <ABSTRACT>Cheap Page Tricks</ABSTRACT>
    </ITEM>
</CHANNEL>

Notice that the first line contains the XML declaration element, a version number, and an encoding declaration. The main entity within the document is the CHANNEL entity, enclosing other elements such as TITLE, ITEM, ABSTRACT, and LOGO. Each of these elements falls within the allowable XML definition for elements:

element ::= EmptyElemTag | STag content ETag 
EmptyElemTag ::= '<' Name (S Attribute)* S? '/>'
STag :: = '<' Name (S Attribute)* S? '>'
ETag::= '</' Name S? '>'
content ::= (element | CharData | Reference | CDSect | PI | Comment )*

Without continuing to resolve the non-terminating references, what the syntax just shown states is that each element is either an empty element, in which case it ends with a backslash/angle bracket combination (‘/>’), or it has start and end tags which enclose content. A “well-formed” constraint is placed on the start and end tags in that the NAME used in both is the same. The enclosed content can include other elements, comments, processing instructions, or other well-formed XML entities. Both empty and non-empty elements can have zero or more attributes, as the following demonstrates:

<CHANNEL HREF="http://www.yasd.com/plus/index.htm" 
        BASE="http://www.yasd.com/plus/">
...
</CHANNEL>

or

<INTERVALTIME DAY="1"/>

Internet Explorer 4.0 has an associated XML parser that pulls the element information out of the document. IE 4.0 uses this parsed element information to create the channel for the Web site, including the two sub-channel items, as shown below:

This site has a main Web page channel, denoted by the top-level graphic, and two sub-channels, with the second sub-channel loaded into the browser.

Accessing the CDF file directly with IE 4.0 opens a dialog box asking the individual how they would like to subscribe to the site’s channel, and allowing the reader to determine how and when the channel contents are downloaded to their client machine.

Other uses of XML
In addition to CDF, Microsoft and Marimba, Inc. have also proposed XML-based technology called the Open Software Description (OSD) format, which can be used to control software downloads and installations over a corporate network. A major IS expense for larger corporations, especially those that are geographically distributed, is installing and maintaining software upgrades on employees’ desktops. One small upgrade to a popular piece of software can take days of planning and weeks of actual implementation (i.e., walking around to each person’s desk and installing the upgrade). During the upgrade rollout, employees will have different versions of the same software, which can create problems. With OSD, software upgrades can be handled automatically using push technology, reducing both IS staff hours and logistical problems.

SGML and XML have both been used to create a Chemical Markup Language (CML) for the chemistry community. With the CML vocabulary, molecular structures can be defined within a document and the information can be either posted or transmitted. XML processors can pull out the CML elements and pass these to applications that perform actions like preparing a print-out of the information, either textually or graphically, or creating an online three-dimensional model of the information using VRML or some other 3D technology.

Netscape, Apple, and others have proposed a Meta Content Framework (MCF) created in XML that can expose a Web site structure for navigation or online exploration. MCF can be used to do such things as generating a three-dimensional site map which can be used for Web site publication and administration. The technology is currently used by Apple’s ProjectX/HotSauce browser, and “Xspace”-compatible content can also be viewed using a plug-in available from Apple.

XML can also be used to define a relational database meta-language, which can then be used to describe documents containing relational database information. These same documents can be easily generated from the relational database dictionaries, which are repositories of information about the information stored in the database. The extensible markup language can then be used to create context-centered documents like “all information pertaining to any purchases, week of January 16 through January 23,” rather than using the context-neutral database format. In addition, supporting information that is not part of the data in the database, like images or reference material, can be pulled into the document.

An XML processor can process this context-based data document and use the information therein to present reports, perform online research and queries, or even to create interactive three-dimensional models of the data. Instead of issuing a SQL statement such as:

select customer_name, customer_address, city, state, zip_code from customer, 
purchase_orderwhere purchase_order.order_id = 32245 and 
customer.customer_id = purchase_order.customer_id;

I could enter a three-dimensional VRML world at a purchase_order portal and scan a virtual filing cabinet for my purchase order number. Once I find it, I can open the door into another room with doors labeled “Purchase Order items” and “Customer” and open the Customer door into another room containing the information I am looking for. Best of all, the documents containing the context-based data could be generated automatically, processed automatically, and presented automatically. This means a change in the database table could be handled automatically.

Besides three-dimensional database applications, defining data in an XML document could be used as a method to convert database data in one format, such as relational data, into another format, such as object- based database records. The resources section at the end of this article has a reference to a preliminary XML representation of a relational database.

In addition, with XML processors (or XML parsers, if you prefer), the most difficult aspect of XML has already been implemented: pulling the entities out of the document.

Returning to the CDF example, not only can the XML document be used by Internet Explorer 4.0 to provide information about the structure of a Web site’s channels, I can also access the XML entities using JavaScript, C++, or Java and use the information for other purposes. For example, the following JavaScript functions open a CDF file, pull out information about the elements contained within the CDF file, and print out this information in a newly opened window.

<script language="jscript">
<!--
var doc = new ActiveXObject("msxml");
var wndw = null;

// display elements in CDF file
// file reference must be fully resolved Internet reference
function DisplayElements(cdffile)
{
// Display this with an appropriate message in a popup window
wndw = window.open("","CDFFile",
"resizable,scrollbars=yes");
wndw.document.open();
doc.URL = cdffile;

// begin displaying elements at root
displayElement(doc.root);

wndw.document.write("</body>");
wndw.document.close();

}

// display element tagname, if any
// and information about element such as any attributes (even 
// if undefined for element) and text and element type
function displayElement(elem) {
if (elem == null) return;
wndw.document.writeln("<p>");
if (elem.type == 0)
    wndw.document.writeln("Document contains element with 
                           tagname: " + elem.tagName);
else
    wndw.document.writeln("Document contains element with no tagname");
wndw.document.writeln("<br>Element is of type: " + 
                                GetType(elem.type) +"<br>");
wndw.document.writeln("Element text: " 
                                + elem.text + "<br>");
wndw.document.writeln("Element href: " 
                                + elem.getAttribute("href") + "<br>");
wndw.document.writeln("Element base: " 
                                + elem.getAttribute("base") + "<br>");
wndw.document.writeln("Element style: " 
                                + elem.getAttribute("style") + "<br>");
wndw.document.writeln("Element day: " 
                                + elem.getAttribute("day") + "<br>");
wndw.document.writeln("Element hour: " 
                                + elem.getAttribute("hour") + "<br>");
wndw.document.writeln("Element minute: " 
                                + elem.getAttribute("min") + "<br>");

// check to see if element has children
var elem_children = elem.children;
if (elem_children != null)
   for (var i = 0; i < elem_children.length; i++) {
      element_child = elem_children.item(i);
        displayElement(element_child);
   }

}

// element type
function GetType(type) { 
if (type == 0) 
        return "ELEMENT"; 
if (type == 1) 
        return "TEXT"; 
if (type == 2) 
        return "COMMENT"; 
if (type == 3) 
        return "DOCUMENT"; 
if (type == 4) 
        return "DTD"; 
else 
        return "OTHER";
}

//-->
</script>

See the Resources section for a pointer to an XML demonstration.

Creating an XML document
A key to the true usefulness of XML is that once an XML parser has been created to process an XML document, you can use it to parse out entity information from any document containing any well-formed XML content.

In the last section, I used Internet Explorer’s ability to parse XML entities, attributes, and content to create a Web page that listed the entities, their attributes, and some content. An interesting example, but not really useful. But what if I were to define my own XML document, including my own XML entities and attributes, and then use IE’s built-in XML parser to create my own graphic menu Web page application? This is fairly simple and only took a couple of hours of playing around to accomplish.

First, I defined my own CDF file and created my own entities, as shown here:

<?XML VERSION="1.0" ENCODING="UTF-8"?>

<DOCUMENT >
    <TITLE>YASD+</TITLE>
    <STYLESHEET HREF="http://www.yasd.com/css/daily.css" />
    <ITEM HREF="http://www.yasd.com/plus/plus.htm">
        <IMAGE HREF="http://www.yasd.com/plus/logo.jpg">
        <ALT>YASD+ Main Page</ALT>
        </IMAGE>
    </ITEM>
    <ITEM HREF="http://www.yasd.com/samples/bytes/daily.htm">
        <IMAGE HREF="http://www.yasd.com/plus/logo.jpg">
        <ALT>YASD Code Byte</ALT>
        </IMAGE>
    </ITEM>
    <ITEM HREF="http://www.yasd.com/samples/bytes/cheap.htm">
        <IMAGE HREF="http://www.yasd.com/plus/logo.jpg">
        <ALT>YASD Cheap Page Tricks</ALT>
        </IMAGE>
    </ITEM>
</DOCUMENT>

I redefined what ITEM is, created a new root element called “DOCUMENT,” and added some new elements of IMAGE, STYLESHEET, and ALT. I followed the XML convention for well-formed entities — opening up this document for parsing within IE 4.0 generates no errors.

I then created an application, consisting of two frames, that uses the images associated with the items to create a graphical menu bar in the top frame of the window and set the link associated with each image to open in the bottom frame of the window. The window originally opens with the form to access the CDF file and process its contents. This form is then overwritten with the processing results. The code for the form and to process the form contents is as follows:

 
<script language="jscript">
<!--
var doc = new ActiveXObject("msxml");
var wndw = null;

var title = "";
var stylesheet = "";
items = new Array();
itemimages = new Array();
itemalts = new Array();
ct = -1;

function createWindow(cdffile)
{
doc.URL = cdffile;

// find main document and any associated item documents
findElements(doc.root);

// if associated documents
if (ct > 0) {
  var strng = "<HTML><HEAD><TITLE>" + title + 
        "</TITLE><LINK REL=STYLESHEET TYPE='text/css'" +  
        " HREF='" + stylesheet + "'></HEAD><BODY>";
  for (var i = 0; i <= ct; i++) 
     strng+="<a href='" + items[i] + 
                "' target='Body'><IMG src='" + itemimages[i] + "' ALT='" + 
                itemalts[i] + "' border=0>" + 
                "</a>"; 
  strng+="</BODY></HTML>";
  document.open();
  document.writeln(strng);
  document.close();
  }
}

// display element tagname, if any
// and information about element such as any attributes (even if undefined for element)
// and text and element type
function findElements(elem) {
if (elem == null) return;
if (elem.type == 0) {
    if (elem.tagName == "TITLE")
        title = elem.text;
    if (elem.tagName == "STYLESHEET")
        stylesheet = elem.getAttribute("href");
    if (elem.tagName == "ITEM") {
        ct++;
          items[ct] = elem.getAttribute("href");
        }
    if (elem.tagName == "ALT") 
        itemalts[ct] = elem.text;
    if (elem.tagName == "IMAGE")
        itemimages[ct] = elem.getAttribute("href");
    }
        
// check to see if element has children
var elem_children = elem.children;
if (elem_children != null)
   for (var i = 0; i < elem_children.length; i++) {
      element_child = elem_children.item(i);
        findElements(element_child);
   }
}
//-->
</script>

I could have defined any elements within the XML document as long as I used well-formed XML entities, and I could process the results in virtually any way I desired just by using simple scripting techniques.

Linking and style information
In addition to the XML specification, other efforts are currently underway to add supporting specifications. The first is XML part 2, which includes linking. Another is XSL, the Extensible Style Language, which defines an XML stylesheet.

Linking has been extended considerably with XML. You can specify an attribute that determines how a resource is displayed, specify whether the resource is displayed automatically, and even specify multiple layers of linkage. Of particular interest is the capability to define a group of links, associating documents together in such a way that the person following the links does not have to hunt around for related documents. If you have ever jumped to a Web site page by following a link from another site, you know how frustrating it can be to try establish the context of the link in order to find related documents.

XSL would be specified using XML and would provide a way to define presentation elements, such as those used currently in HTML. For example, HTML includes the Emphasis element, delimited with <EM> </EM> tags, the Strong element, delimited with <STRONG> </STRONG>, and others. With XSL, you could create styles to provide recommendations for how an XML entity is rendered.

The downside to XML
While XML’s implementation-neutral technique allows parsed information to be used for multiple purposes in multiple applications, it is this same flexibility that may cause problems.

Returning one last time to my CDF example, I created a simple JavaScript application that opens the main channel page and all the associated pages into a frames-based Web page. The main page opens into the top-most frame, and each individual CDF ITEM element opens into one of the smaller frames located along the bottom of the document.

This isn’t a problem for my own CDF file, which is relatively simple. Applying the same application to another CDFfile, however — one I neither created nor control — creates a Web page that probably does not meet the expectations of the page’s designer. The following screen shot shows the result of using the frames-generation application on the IDG.net channel:

To create this page, I used a publicly accessible file, IDG.net’s CDF file, and exposed the XML elements to create a presentation neither Microsoft nor IDG.net intended. Even with the new effort on XSL, currently only a W3C proposal, there is no guarantee that the information exposed with XML will be used for anything approaching the intended purpose of the XML document’s original creator.

Another potential problem area with XML is the CDF specification. CDF’s potential is great; you could use it to build an XML-based document that could be used by different push technology vendors with relatively comparable results. But what happens if a vendor supports channels but doesn’t want to use CDF? Do we end up with different “flavors” of channels? Does the W3C then create a different standards specification for channels, another for chemistry, another for math, another for finance, and so on in order to ensure that only one specification for each “topic” or “business” is created? Or can we design tools for translating between each of the XML document definitions?

In conclusion
Even with these issues at stake, XML is a terrific addition to Web and other application development. One of the most difficult aspects in application programming is extracting the structure as well as the contents of documents. XML has made this process a whole lot easier.

During the recent XML/SGML conference in Washington DC (December10-12), XML became a proposed recommendation of the W3C, the last remaining step before becoming a real recommendation. It may be only a matter of time before XML is just as common as SQL is today.

Netscape Navigator’s JavaScript 1.1 vs Microsoft Internet Explorer’s JScript

Originally published at Digital Cats, now archived at the Wayback Machine

Prior to Netscape implementing JavaScript in Netscape Navigator, web developers had few tools to create interactive content for their web pages. Now this scripting language gives developers the ability to do things such as check form contents, communicate with the user based on their actions, and modify the web page dynamically without the web page being re-loaded and without the use of Java, plug-ins or ActiveX controls.

Unfortunately, JavaScript was not usable by any other browser until Microsoft released Internet Explorer (IE) 3.0. With this release web developers could deliver interactive content that would at least work with the two most widely used browsers. Or could they?

On the surface, the JavaScript supported by both companies is identical. They both provide the same conditional control statements, have defined objects such as window or document,and can be used directly in HTML documents. They both support events based on user actions and support functions in a similar manner. However, this article will demonstrate that though the languages may look the same on the surface, there are differences that can trip the unwary developer.

JavaScript Objects

To understand the differences between the two implementations of JavaScript you must examine the objects both support. As an example, with Navigator 3.0 Netscape provides a new object image which is an array (defined as images that contains the images in the document currently loaded. This object allows the developer to change the images of a document without re-loading the document or using Java or other technique. With this capability the developer can write the following JavaScript code section without error:


sSelected = "http://www.some.com/some.gif"
document.images[iIndex].src = sSelected

This code will change the src property of the image that is contained in the array at the index given in the variable iIndex. If this variable contained the value 2, the 3rd image as loaded in the document (the array indices begin at 0) would be changed to the image located in the given URL. An example using images can be found here.

Running the same example with Internet Explorer will result in a alert message that states that “‘images’ is not an object”.

Other examples of objects that are defined for Netscape Navigator but not for Microsoft Internet Explorer are:

  • The Area object, which is an array of links for an image map that allows the developer to capture certain events for the image map that can be used to provide additional information to the user. With this, the developer can capture a mouseOver event to write out information about the link in the status bar.
  • The FileUpload object which provides a text like control and a button marked with “Browse” that will allow a reader to enter a file name. The JavaScript can then access the name of the file.
  • The Function object which allows the developer to define and assign a function to a variable which can then be assigned to an event.
  • The mimeTypes Array of supported MIME types.
  • The option object which is an array of the options implemented for SELECT and which allows the developer to change the text of the option at runtime
  • The applet object, which is an array of Applets in the document (read-only)
  • The plugin object, which is an array called embeds that contains the plug-ins contained in the document (read-only)
  • The plugins array, which is an array of plug-ins currently installed in the client browser

At this time there are no JavaScript or JScript objects defined for Internet Explorer that are also not defined for Netscape. However, as JScript is an implementation script for IE and Microsoft has defined their own IE scripting model, this could change in the future.

JavaScript Object Behavior and Ownership

Internet Explorer may not have additional objects but it has defined a different hierarchy and ownership for some of the objects that are used by both it and Navigator. All objects are contained within the window object in the IE scripting model, which can be viewed here, but not all objects are owned by window with the Navigator model, which can be viewed with the JavaScript Authoring Guide. The object Navigator, which is the object that stores information about the browser currently being used, is an example of an owned object by window in IE but not in Navigator.

This will not present an incompatibility problem between the two browsers as the developer will usually not preface the object with the term “window” as the following code demonstrates:


<FORM NAME="form1">
<input type=button value='press' onClick="alert(navigator.appName)">
</FORM>

The above code will work with both browsers.

The differences between the ownership can become a problem when an object is owned by different levels of objects. An example is the history object, which is owned by the window object in IE, but by the document object in Navigator. When used in the current window and document, the object will work the same as the following code will demonstrate:


<FORM NAME="form1">
<input type=button value='press' onClick="history.back()">
</FORM>

The reason the same code can work for both is that window is assumed for both IE and Netscape and document is assumed for Navigator, at least in this instance because history is also an object in its own right. In the case of a document being opened as part of a frame, the differences then become noticeable. The following code will work when the document is opened as a frame in IE, but will not work in Navigator:


<body>
<script>
function clicked() {
history.back()
}
</script>
<FORM NAME="form1">
<input type=button value='press' onClick="clicked()">
</FORM>
</body>

Clicking on the button from the code above will work for IE. The previous document in the History list will be opened, but the same code will not work for Navigator. Clicking on the button will result in neither a change of document nor an error. Prefacing the history object with parent will enable this code to work with both browsers.

JavaScript Properties

Even when IE and Navigator share a common object and a common object ownership, they can differ on the properties for an object. An example is the document object. The properties for both implementations are the same except for an URL property for the Navigator implementation and a location property for the IE implementation. However, if you examine both properties, they are identical! Both contain the URL of the document. Both are read-only. The following code will work with Navigator, but results in an empty Alert message box for IE:


<FORM NAME="form1">
<input type=button value='press' onClick="alert(document.URL)">
</FORM>

According to Microsoft documentation, the equivalent for IE would be to use document.location.href. However, though this does not result in an error, it also results in an empty alert box. The following code achieves the desired results and, happily, works in both browsers:


<FORM NAME="form1">
<input type=button value='press' onClick="alert(location.href)">
</FORM>

The above example does demonstrate another area of caution when using the JavaScript language: this language is unstable in both environments and is changing continuously. Don’t assume something will work because the documentation states it will, and don’t assume it will work the same on all operating systems. Both browsers can have different behaviors across different operating systems, sometimes because of operating system differences and sometimes because of bugs that were missed during testing on that specific OS.

JavaScript Methods and Events

A web developer can find ways of working around differences in objects and properties, but working around differences in methods may not be so easy. When we develop we expect a certain behavior to result when we call a specific function and pass to it certain parameters. With Microsoft Internet Explorer and Netscape Navigator, the best case scenario is that we can use a pre-defined object method with both browsers and have the same result. The worst case scenario is that the method works with both browsers, but the result is different.

An example of the best case scenario is to use JavaScript to validate form field contents which have changed or to use these contents to calculate a value used elsewhere. Calling a JavaScript function from the onChange event to process the changed contents as demonstrated below will work with both browsers:


<!--- Form fields
<p>Item Quantity: <INPUT TYPE="text" Name="qty">
Item Cost: <INPUT TYPE="text" Name="cost"
                onChange="NewCost()">
Total Cost: <INPUT TYPE="text" Name="total" Value=0>
…
<!--- Function
<SCRIPT LANGUAGE="javascript">
<!--- hide script from old browsers

// NewCost will
// calculate cost of qty and item
function NewCost() {
        var iCost = parseFloat(document.Item.cost.value)
        var iQty = parseInt(document.Item.qty.value)

        var iTotal = iCost * iQty
        document.Item.total.value = iTotal
        }

The above will work as expected with both IE and Navigator. When the user enters a quantity and a cost, the onChange event will fire for the cost field and a JavaScript function called NewCost() will be called. This function will call two built-in JavaScript functions, parseFloat() and parseInt(), to access and convert the form field values. These will then be used to compute a total which is placed in the total field.

So far so good. Another JavaScript function in the web page will be processed when the user presses the submit button. This pre-defined button style will normally submit the form. The developer can capture the submission and perform validation on the fields. Coding this for Navigator would look like the following:


<FORM NAME="Item"
        ACTION="some.cgi" onSubmit="return SendOrder()">
…
<!--- Function
// submit order
function SendOrder() {

        // validate data
        if (document.Item.Name.value == "") {
                alert("You must enter your name")
                return false
                }
        return true
        }

Capturing the onSubmit event will allow the developer to call a function to process the form fields. If they choose, they can perform validation in this function. If the validation fails, say the user did not provide a name, the function notifies the reader and returns false, preventing the form from being submitted. If the user did provide a name, the function would return true, and the form would be submitted.

Following the documentation that can be found at the Microsoft site, the developer would expect something like this to work for IE as well as Navigator. It does, to a point.

With IE the onSubmit event is captured and the SendOrder() function is called. If the user did not enter a name value, an alert would occur. The behavior is the same for both browsers at this point. However, if the user does provide a value, Navigator would then submit the form and a follow-up form would be displayed. This does NOT occur with IE IF you are testing the page locally, probably due to a bug missed during the testing. It does work if you run the web page documents through a web server.

However, without knowing that the difference between the two results was a matter of document location rather than document coding the web page developer could have spent considerable time trying to get the same behavior for both browsers.

Aside from the differences already noted, the browsers may process code in a funtionally identical manner and yet perform quite differently. This can be demonstrated with another popular use of JavaScript which is to open a secondary window for some purpose and to maintain communication between the two windows. This is widely used by Netscape for their tutorials.

Both browsers support a property for the window object called opener. This property can be used to contain a reference to the window that opened the secondary window.

The following code demonstrates using JavaScript to open a secondary window and to set the opener property to the original window:


<HTML>
<HEAD><TITLE> Original Window </TITLE>
<SCRIPT LANGUAGE="JavaScript">
<!--- hide script from old browsers
// OpenSecondary will open a second window
//
function OpenSecond(iType, sMessage) {
        // open window
        newWindow=window.open("second.htm","",
                "toolbar=no,directories=no,width=500,height=300")
        // modify the new windows opener value to
        // point to this window
        if (newWindow != null && newWindow.opener == null)
                newWindow.opener=window

        }
// end hiding from old browsers -->
</SCRIPT>
</HEAD>
<BODY>
<H1> Open a new Window and get information</H1>

<FORM NAME="CallWindow">
<p>Click to open Window:
<p>
<INPUT TYPE="button" NAME="OpenWin" VALUE="Click Here"
        onClick="OpenSecond()">
<p>
</FORM>
</BODY>
</HTML>

The above HTML and JavaScript creates a simple document with one button. Pressing the button opens a new window (creates a new instance of the browser) that does not have a toolbar or directories and is set to a certain width and height. The HTML source document that is opened into this new window is “second.htm”.

The HTML and JavaScript in the secondary window is shown below:


<HTML>
<HEAD><TITLE> Information</TITLE>

<SCRIPT LANGUAGE="JavaScript">
<!--- hide script from old browsers
// SetInformation
// function will get input values
// and set to calling window
function SetInformation() {
        opener.document.open()
        opener.document.write("<BODY>")
        opener.document.write("<H1> Return from Secondary</h1>")
        opener.document.write("</BODY>")
        opener.document.close()
        opener.document.bgColor="#ff0000"
        window.close()
        }
// end hiding from old browsers -->
</SCRIPT>
</HEAD>
<BODY>
<p><form>
Click on the button:<p>
<INPUT type="button" Value="Click on Me"
     onClick="SetInformation()">
</CENTER>
</FORM>
</BODY>
</HTML>

This code will display a button labeled “Click on Me”. Pressing this button will result in the document page for the original window being modified to display the words “Return from Secondary”. The JavaScript will also change the background color of the original document and then will close the secondary window. When run in Navigator, the sample behaves as expected. Not so, however, with IE.

First, when you open the secondary window in IE you will notice that the document in the original window seems to blank out for a moment. In addition, the secondary window opens at the top left hand side of the desktop with IE but opens directly over the original window with Navigator, no matter where that original window is.

When you press the button that modifies the original document, IE does modify the document with the new header, as Navigator does, and the background on the original document will change briefly. However, when the secondary window is closed the background color of the original document returns to the original color!

What is worse is that running this sample for a few times with IE will cause the browser to crash! How soon it will crash seems to suggest that resources are not being freed, or are being freed incorrectly. Whatever the cause, this behavior should make a developer feel cautious about opening up a secondary window within IE.

Solutions to working with both Internet Explorer and Navigator

JavaScript is a useful tool for creating interactive content without using Java or some other technique. As we have seen, problems arise out of the incompatibility between Navigator and IE. What are ways to avoid these problems?

  • Code for one browser only. This is not really a viable solution. While Netscape Navigator is the most popular browser in use today, Microsoft Internet Explorer is gaining quite a following. Using Navigator-only JavaScript that will limit your web page’s audience.
  • Code only to the least common denominator. By limiting the JavaScript to that which works for both Navigator and IE, developers will have access to most of the functionality they need. However, with this approach developers will need to be aware of the gotchas that have been discussed in this article. In other words, the developer has to test with both browsers; the tests will have to occur via the web server as well as run locally; the tests should be repeated several times to ensure that no adverse effects show up over time; the code should be tested with all possible environments.
  • Code for each browser within the same page. This is actually my favorite approach though it will require more effort by the developer. Both browsers will process JavaScript labeled as <SCRIPT LANGUAGE=”javascript”>, however only Navigator will process script labeled as <SCRIPT LANGUAGE=”javascript1.1″>. With this approach, the developer can place JavaScript common to both browsers in a SCRIPT tag labeled with “javascript” and Navigator specific code in a SCRIPT tag labeled with “javascript1.1”. To add in IE specific code, the developer would probably want to use VBScript code or use the tag JScript whenever applicable. At this time, JScript is implemented for scripting with events only, not as a language specification for the SCRIPT tag.

Summary

JavaScript is a very effective tool, and a relatively simple method for adding interactive content to a web page. With version 3.0 of Internet Explorer, using JavaScript is viable for both of the most popular browsers in use. However, developersneeds to be aware of the differences between Netscape Navigator and Microsoft Internet Explorer and should test thoroughly with both before posting the page to their site.

Using Dynamic HTML to create an animated menubar

Originally published in Netscape World, now archived at the Wayback Machine

Microsoft and Netscape decided to use two different techniques for Dynamic HTML. Microsoft bases its approach on exposing CSS1 (Cascading Style Sheets) attributes to script, with a little help from some interesting new built-in, lightweight, and windowless ActiveX controls. Netscape bases much of its approach on the new LAYER tag.

At first glance, the approaches seem incompatible — using one browser’s techniques will not work with the other. However, you can use both browsers’ techniques within the same page and generate the exact same result.

In this article, I create an animated menu bar using a combination of CSS1 style sheets, the PATH ActiveX control, and dynamically modifying HTML elements to work with IE 4.0. I create the exact same effect using CSS1 style sheets and the LAYER tag for Navigator 4.0. Note, though, that both IE 4.0 and Navigator 4.0 are works in progress, and this example may need to be modified, slightly, for future versions of either product.

Creating style sheetsThe first section of the example page is the CSS1 style sheet settings. Both IE 4.0 and Navigator 4.0 process these style sheets, though Navigator does not seem to like setting images using the IMG tag at this time.

This example image uses headers for the text-based portion of a menu bar. To create the effect I want, I don’t want the standard underline that occurs with hypertext links, and I do want to modify the font size and color. As I don’t want either of these changes to impact on the rest of the document, I use the cascading effect of CSS1 to apply these changes only to links contained within <H2> header tags:

h2 A { text-decoration: none; color: gold } 
h2 A:link { color: gold } 
h2 A:visited { color: gold }

Next, I create the style sheet definitions for the menu images, for use with IE 4.0 only. I use absolute positioning to place the images exactly where I want on the page, and use the visibility property to hide the images when the page is first opened:

#menu1 { position: absolute; left: 0; top: 0; 
	visibility: hidden}
#menu2 { position: absolute; left: 142; top: 0; 
	visibility: hidden}
#menu3 { position: absolute; left: 284; top: 0; 
	visibility: hidden}
#menu4 { position: absolute; left: 192; top: 0; 
	visibility: hidden}
#menu5 { position: absolute; left: 142; top: 192;
	visibility: hidden }
#menu6 { position: absolute; left: 284; top: 192; 
	visibility: hidden}

The final part of the CSS1 style sheet definition creates the text-based menu components of the menu bar. These show as soon as the page is opened, and if the Web page reader does not want to wait for the images, or has image downloading turned off, they can access the links via the text menu. The size of the area for the menu text item should be large enough to contain the complete text, otherwise odd behavior will result with Internet Explorer: It does not display the text correctly when you click on a text-based menu item. Another text-based style sheet rule is provided for a message that is displayed while the images are loading. Whenever you create content that may be invisible or not displayed for a time, provide some kind of feedback to the user about what is happening:

This is the final section of the CSS style sheet definitions.

Adding images to a Web pageThe next section in the example page is the scripting, but I will talk about that a bit later. For now, I will add the images to the Web page using two different techniques, one for IE 4.0, and one for Navigator 4.0. IE 4.0 uses the style sheet settings defined for the images, and references the appropriate definition by using the identifier of the style sheet rule. The Navigator technique is to embed the images within layers that are hidden when the page first loads. IE 4.0 ignores the LAYER tag, and Navigator ignores the image style sheet rules:

Note that a hypertext link reference is applied to the image, and the border is set to 0. As the image style sheet rules seem to be ignored by Navigator, important image information such as widthheight, and border are specified within the image tag.

Next, the text objects are added to the menu bar. This includes a text-based alternative that labels each image when it is displayed, or can be accessed directly if the image is not displayed. This also includes a message stating that the images for the menu bar are being loaded:

The “waiting…” text is placed within a LAYER tag as I need to add script to modify it later, and only layer-based elements can be modified with Navigator at this time.

The final objects to add to the page are six ActiveX PATH objects, to control the menu bar animations for IE 4.0. A path object can be used to specify both X and Y coordinates at specific tick marks and moves the visual object associated with the control along that path. Two of the parameters for the control are the X path coordinates and the Y path coordinates. Another parameter could also control the timer, but I want to synchronize my image movement, so I use a different script-based approach later:

Notice that the X, Y coordinates for each path object are different, but all of them have the same number of timing ticks, which is the first parameter given in each of the coordinate pairings. The tick timings given are in microseconds.

The PATH ActiveX controls are the last elements placed into the page. Next comes the fun part, animating the menu bar.

Adding the script to animate the menu barThe animation is started when the page loads by trapping the onLoad event for the document. This calls a function called cycle. This function is implemented in both VBScript and JavaScript, and the appropriate browser picks the appropriate implementation, with Microsoft grabbing the VBscript version, Navigator grabbing the JavaScript version.

The first script controls the menu bar for IE 4.0. This is written entirely in VBScript, though JavaScript could be used if browser differences are handled correctly. The cycle function sets the Target properties of the path objects to the style sheet rules of the menu bar images. This associates each path control with its visual object. Next, the images are set to be visible, and the “waiting..” text is hidden.

The Play method for each path control is called, beginning the animation process, though no movement occurs yet. Why? No movement occurs because no timing mechanism has been associated with each control. The timing is handled by using the setTimeout function and calling a second subroutine that handles the image animation. The complete text of the cycle subroutine is here:

I use my own timer to synchronize the images, a technique that Microsoft recommends when using more than one PATH control on the same Web page.

The MoveIEObjects subroutine calls the Tick method for each of the path controls, moving each of the objects to the next coordinate defined for the specific control. It issues another setTimeout function call to continue the animation process, after first testing to see if the last movement of the path has occurred (the last of the ticks, of which there are eight for this particular demonstration). Note that I did not necessarily have to test the tick movement because after the path has completely played, it no longer moves unless it is rewound. However, I want to make sure the timer is not still operating. The complete text of MoveIEObjects is given next:

Next, I add the JavaScript to control the animation for Navigator 4.0. The cycle function for Navigator is similar to that for IE 4.0, except that I need to create my own arrays of X and Y coordinates. These arrays, in turn, are set to hold other arrays holding the actual coordinates. After the arrays are created, the images are displayed and the timer is started, as seen next:

The final script is for the MoveObjects function for Navigator. The LAYER tag method moveTo is used to move each of the images to the new coordinate for this timer event. Note that the timer values are set to be much larger than the ones set for IE 4.0 as the PATH control does run a bit slower than using the LAYER tag approach, and I wanted both effects to be as similar as possible. MoveObjects can be seen next:

Note that resizing Navigator can misalign the images. Netscape recommends a blank document.write statement in JavaScript to compensate for this type of problem, but this does not work for this example. I will continue to investigate this and will post a fix to my Web site when one appears. In the meantime, if you resize the Web page you need to reload the example. No problem occurs when you resize IE.

That’s it for the scripting. You can test the example yourself if you are using either IE 4.0 or Netscape 4 (this script will not work on earlier browsers). View the complete source by using the appropriate “View Source” option of your browser.

 

Adding dynamic content for multiple browsers & versions

Originally published in Netscape World May 1997, archived at Wayback Machine

One concern facing all Web developers when Microsoft or Netscape release a new version of Navigator or Internet Explorer is how to incorporate some of the new technologies of the new versions, but still offer Web pages that are readable by older versions of the browser. The developer could consider forcing those people who view their pages use the newer versions of the browser, but this approach limits your audience, something most Web sites want to avoid.

Neither is it feasible for a Web site to limit their pages to those viewable only by one browser. Microsoft Internet Explorer has been steadily gaining market share since the release of IE 3.0. Most Web sites will need to develop content that will work with at least two versions (the current released version, and the version that is in preview release) of each of the major browsers. The good news is that there are techniques to use to enable this cross-browser, cross-version capability. The bad news is that each of the techniques will require additional and, at times, extensive effort.

This article demonstrates two techniques to manage browser and version differences at a Web site. The first uses scripting to determine the type and version of the browser, and re-directs the browser to load a specific page. The second uses scripting and style sheet techniques to generate content, in one page, viewable by different browsers and versions. The article will also detail some rules of thumb to follow when creating a browser friendly Web site.

There is more than one way to re-direct browser input. One tactic is to create a separate Web page for each browser and each browser version that they want to support, and then have a CGI program load the appropriate Web page based on which browser and version is accessing the page. This is not a bad approach, and it works well if you want to support browsers that don’t handle scripting.

A scripting approach based on browser and version, is to trap the onLoad event for the browser page, and re-direct the Web page output to another page. You trap the onLoad event in the <BODY> tag, using the following code:

<BODY onLoad="change_document()">

The change_document function uses the navigator properties of appVersion and appName to find out which brower and version are being used to access the page. This is then used to create a string containing the URL of the re-directed output:

<SCRIPT Language="JavaScript">
<!--
   function change_document() {
      var MS=navigator.appVersion.indexOf("MSIE")
	var MSVER = parseInt(navigator.appVersion.substring(MS+5, MS+6))
    	var NSVER=parseInt(navigator.appVersion.substring(0,1))
	var locstring
	if (MS > 0) 
		locstring = "diffie" + MSVER + ".html"
    	else if (navigator.appName == "Netscape")
		locstring = "diffns" + NSVER + ".html"

	window.location = locstring
   }
//-->			
</SCRIPT>

To see an example of script re-direction, try this diff sample.

The downside to this type of browser and version difference handling is this: if you want to support Netscape Navigator 2.x, 3.x, 4.x, in addition to Internet Explorer 3.x and 4.x, you will need to create five pages for each Web “page” at your site!

However, this approach is effective if you wish to apply it selectively at your site. Perhaps you want to have an interactive product page that makes use of all the fun dynamic HTML techniques each browser is implementing. This approach could be used for this product page only, giving you the freedom to use the specific browser/version technology to its fullest.

Another technique to handling browser/version differences is to use scripting and style sheets in one page and ensure that the scripting is directed at the appropriate browser and version.

I will demonstrate this with the next sample code. The example will change the background color for all of the browsers and versions. This is all it will do for Netscape 2.x. For Internet Explorer 3.x, a CSS1 style will also re-define the appearance of the <H1> tag. For Netscape 3.x, the image that displays when the document first opens is changed. For IE 4.0, the image is changed and the style sheet definition for the <H1> tag also changes (both the font size and color). Finally, for Netscape 4.0, the <H1> tag is also changed, but this time using Dynamic Style Sheets (DSS), meaning that JavaScript has been applied to JavaScript Style Sheet (JSS) elements.

First, I apply some style sheet definitions for the Web page. A JavaScript style sheet and a standard CSS1 (Cascading Style Sheets) definition are created:

<STYLE TYPE="text/JavaScript">

	classes.class1.H1.fontSize="24pt";
	classes.class1.H1.color="green";

	classes.class2.H1.fontSize="18pt";
	classes.class2.H1.color="red";

</STYLE>
<STYLE TYPE="text/css">
	H1.newstyle { font-size: 18pt ; color: red }
		margin-top: -.05in ; margin-left: 1.0in } 
	H1 { font: 24pt ; color: green }

</STYLE>

These style sheet definitions provide for new formatting for the <H1> tag, and will be used in JavaScript functions that will be created a little later in this article.

Next, global variables will be defined that contain the type and version of the browser accessing this page. As these are global in nature, they will be available anywhere that JavaScript is used in the page:

<SCRIPT Language=JavaScript>
<!--
var MS=navigator.appVersion.indexOf("MSIE")
window.isIE4 = (MS>0) && 
    ((parseInt(navigator.appVersion.substring(MS+5,MS+6)) >= 4) &&  
    (navigator.appVersion.indexOf("MSIE"))>0)

var NSVER=parseInt(navigator.appVersion.substring(0,1))

isNS4 = false
isNS3 = false

if (navigator.appName == "Netscape") {
   if (NSVER == 3) {
	isNS3 = true
	}
   else if (NSVER >= 4) {
	isNS3 = true
	isNS4 = true
	}
   }

The next script is a function, change_doc, which will change the background color for the Web page for all versions of the browsers that access it. Additionally, if the browser is Netscape 3.x or 4.x, it calls another JavaScript function, change_document3:

function change_document() {
  	document.bgColor="beige"

    	if (isNS3) 
		change_document3()
	}

The next JavaScript function is change_new which is only called by IE 4.0. This function will apply the new style definition for the <H1> tag that has an id of “myheader”, using Microsoft’s own version of Dynamic HTML:

function change_new() {
	var chgh1 = document.all.myheader
    	chgh1.className = "newstyle"
	}
//--> 
</SCRIPT>

The scripting block is closed as the other functions will be creating in different versions of JavaScript. First, using JavaScript 1.1. we create the change_document3 function which will change the image shown in the  page. At the end of the function the value of the isNS3 is tested, and if true the function change_document4 is called. Note from the global variable section that isNS3 is set to true for both Netscape 3.x and Netscape 4.x:

<SCRIPT Language="JavaScript1.1"> 
<!--
function change_document3() {

    	if (!isNS4) 
	     document.thisimage.src="sun.gif"
    	else
	     change_document4()
	
	}
//-->
</SCRIPT>

Using the JavaScript 1.1 specification means that any script within this block will only be executed by a browser that is capable of processing JavaScript 1.1 script. This includes Netscape 3.x and 4.x, as well as IE 3.0x and 4.x.

The next function is change_document4, which is created in a JavaScript 1.2 scripting block. This function will be called only for Navigator 4.x. The script uses a <LAYER> tag to encapsulate the original contents of the page. When this function is called, those contents are hidden, and new contents are created using a new LAYER object:

<SCRIPT Language="Javascript1.2">
<!--
  function change_document4() {
	document.layers[0].visibility="hide"

	// note with following...another technique would be to 
	// create a second layer, set to invisibile, and use 
	// conditional comments to block for non-layer browsers...
	// not implemented, yet
	newlayer = new Layer(600)
	newlayer.visibility="inherit"
	newlayer.document.write("<img src='sun.gif' width=76 height=76 alt='sun'>")
	newlayer.document.write("<H1 class=class2> Header for this example page </H1>")
	newlayer.document.close()
	}
//-->
</SCRIPT>

I close the <HEAD> section. In the <BODY> tag, we trap the onLoad event for the Web page. This event will check to see if the browser and version is Internet Explorer 4.0. If it is, the change_newchange_document, and change_document3 functions are called. For the other browsers/versions, only the change_document function is called. Additionally, I create the image definition and <H1> contents:

<BODY 
onLoad="if (window.isIE4) {change_new(); change_document(); change_document3();} else change_document();">
<LAYER>
<img src="rain.gif" width=76 height=76 alt="rain" name="thisimage">
<H1 id=myheader> Header for this example page </H1>
</LAYER>

Let’s take a look at this sample page in action.

This approach is just one of many that could be taken to determine the browser and version, and only execute the appropriate scripting. Different scripting blocks were used for the different versions of Navigator as there will usually be other functions and event handlers that will be coded and that are only implemented with the specific version. As an example, a new object for Navigator 3.x was the IMAGE object, for Navigator 4.x, it is the LAYER tag. Enclosing the code in these scripting specific versions ensures that a browser that is not capable of processing the object does not process the code.

One nice feature that Netscape implemented in Navigator 3.x, and I hope it continues to implement with version 4, is the ability to provide overloading of functions based on versions of JavaScript. As an example, I created this test page that splits the functionality completely by JavaScript version. Each version has a function called change_document(). Navigator 2.x and Internet Explorer 3.x will access and execute the script it finds in the topmost “JavaScript” block. Navigator 3.x will go for the section with the <SCRIPT LANGUAGE="JavaScript1.1"> tag.

As I write these words, Navigator 4.0 does not go for the section for JavaScript 1.2, but I will continue to test for this functionality and hope to see this in a future preview release, or the final release. IE 4.0 does execute the script in the JavaScript 1.2 section. Add in a little use of navigator.appName and you can duplicate the functionality created earlier by having the browser execute the right script by default.

Unfortunately, Microsoft does not seem to support the concept of versions with the use of VBScript (if it does, please let me know).

Browser-friendly Web page rulesHere are some good rules of thumb I use when creating browser-friendly Web sites.

1. Know your audience
Most of the people that visit my site are Web page developers, and I can alter and play with the contents knowing that most people viewing my site will be using the newest browsers, and most likely are using Navigator and Internet Explorer. If your Web site is for a bank, or a book company, or other non-computing related company, you may not want to use too much new technology.
2. Make a decision on browser support
After stating rule 1, I will now extend it by saying that you can’t please all the people all the time. You will want to make a decision as to whether the cost of providing support for a specific browser is worth the possible loss of visitors to your site.
3. Integrate new technology unobtrusively
If you create one page for multiple browser/versions, make sure you use technology carefully, and in such a way as to not take from the overall style and meaning of the page. With the example shown in the last section, the page dynamically changes based on the browser, but the overall content (what there is of it) is not changed. Reserve your wilder instincts for special fun pages and then implement the first technique given in this article to load browser specific pages.
4. Always provide at least one text based page for your site, if not for each Web page
On pages where navigation is crucial, make sure you offer text-only links for users of obscure or non-graphical browsers, such as Lynx. Again, though, balance this with your known audience.
5. Be aware of those with special physical challenges
Do not use image maps without providing a text-based menu. Always provide an ALT property for any images you use. Do not rely on the newer technologies as the only method for communicating an idea, a product, a service, or for site navigation.
6. Test your Web pages with your target browsers and versions
Once you decide which browsers and versions you are supporting, always test your Web pages with all of them. This may mean you have to use multiple machines, or a system with dual-booting operating systems.
7. Have fun
If you find yourself becoming incredibly frustrated with trying to get something that works easily with one browser or version, to work with another, you might want to stop, walk away, take a break and then try approaching your scripting challenge from a different perspective. If something will not work, then find what does work and find a way to apply it to your current problem.

Happy scripting!