DETECTING A JAVASCRIPT CLIENT

by Danny Goodman

Unless you're developing HTML pages for an intranet environment -- where you know the browser version on virtually every client machine -- you're perhaps painfully aware that not everyone accessing your pages can benefit from your scripting efforts. At one extreme is the client running the latest release version of a browser capable of interpreting JavaScript 1.1, the version delivered with Netscape Navigator 3.0. At the other extreme are those visitors who use text-only browsers, such as Lynx. In between are dozens of browser brands and versions. Some can interpret JavaScript 1.0; others understand only Internet Explorer's version of JavaScript; and still others haven't a clue about the HTML scripting embedded in your documents.

Managing browser-specific features has been a problem for Web authors and Web masters ever since the first HTML extension found its way into early browsers. With each new generation of modern browsers, the universe of visitors to our pages fragments ever more, forcing us to make difficult decisions about how to treat a variety of browsers. If you're a scripter, it's only natural to think about using JavaScript as an aid to sorting out browser versions.

WHOOPS NO JAVASCRIPT

Sometimes I think we scripters get too entwined in our JavaScript-enhanced worlds to distinguish between the forest and its trees. I've lost count of the number of newsgroup requests for a script to help a page detect whether or not the browser is JavaScript-enabled. Perhaps the existence of the javaEnabled() method of the Navigator object leads some scripters to expect a corresponding javaScriptEnabled() method.

What these folks fail to realize is that a non-JavaScript browser cannot run such a script...or any script. Therefore, you cannot script an if...else control structure to document.write() one batch of stuff to a page if JavaScript is enabled and a different batch of stuff if JavaScript isn't there (or if it's turned off).

Another dream tactic is to employ a script to overwrite HTML that would be displayed in non-JavaScript browsers. This, too, isn't possible: Any standard HTML in a document will appear in all browsers from Lynx to Communicator. JavaScript cannot inhibit HTML content display.

DETERMINING THE REAL NEED

While I can't cover every possible scenario in which you might like to distinguish between JavaScript- and non-JavaScript-aware browsers, I see three basic strategies you could use to accomodate browser with different levels of JavaScript awareness. They are:

I believe you can adapt one of these methods to fit most script vs. non-script situations -- including those that might otherwise seem hopeless. Solutions range from the very simple to ones that take a fair amount of forethought and careful execution. In all cases, think of JavaScript as a page enhancement tool: When the browser is JavaScript-enabled, the page does something more than when the page is viewed in a non-JavaScript browser.

A BRANCHING INDEX PAGE

In keeping with my belief that scripting should work silently in the background, without great fanfare, I avoid deploying index.html pages that rely on the site visitor knowing about his or her browser. While Web page authors are extremely sensitive to browser brands and levels, the increasingly large audience of non-nerds surfing the World Wide Web has little, if any, emotional attachment to the browser being used at any moment. To provide an index.html page with two or more links labeled for specific browsers won't help someone who doesn't know exactly what's inside his or her WebTV box.

(Aside: The height of geek bravado must be a site I visited recently [URL withheld so as not to embarrass the page's author] that provided a link labeled for users who had browsers that were HTML 3.2-compatible and a link for those whose browsers weren't up to that level.)

But you can craft the index.html page to branch to many different tracks through your site. The tactic is based on first displaying a nearly content-less index.html page that isn't the true home or welcoming page to your site. Instead, it displays a lone image of any size (perhaps a logo) in the same page location as that image appears in the true home page for each of your browser-dependent tracks.

Let's look at a typical index.html page that provides branches to two tracks in a site: A scripted track that starts at home1.html and an unscripted track that starts at home2.html. The HTML is shown in Example 1.


Example 1

<HTML> 
<HEAD> 
  <TITLE>GiantCo OnLine</TITLE> 
  <SCRIPT LANGUAGE="JavaScript"> 
  <!-- 
      window.location = "home1.html" 
  //-->
  </SCRIPT> 
  <META HTTP-EQUIV="REFRESH" CONTENT="1; URL=http://www.giantco.com/home2.html"> 
</HEAD>

<BODY> 
<CENTER> 
   <A HREF=home2.html><IMG SRC=images/giantcoLogo.gif HEIGHT=60 WIDTH=120 BORDER=0 ALT="GiantCo Home Page"></A> 
</CENTER>
</BODY> 
</HTML> 


Here is how three different level of browsers react to this index.html page:

Let me add the following four points about Example 1:

  1. Notice that the tag contains no color attributes. Even if the home pages have background colors or patterns set, it is best to leave the index.html page plain. Otherwise the screen will flash from color to plain to color in the switch from index.html to the home page.
  2. I chose not to display a link border around the image so that the border doesn't appear and then disappear for those with JavaScript or modern browsers.
  3. If you want to make sure that the JavaScript-enabled browser is compliant with JavaScript 1.1 only, then change the <SCRIPT> tag's LANGUAGE attribute to "JavaScript 1.1". In that case, all JavaScript 1.0-only browsers will respond to the <META> tag instead.
  4. You can use the script in the <HEAD> portion to perform any kind of browser validation checks you like before setting the location object. For example, if your super-duper scripted home page requires a plug-in, you can check for it there. Or if you have further subdivisions of your home page tracks based on browser operating system platform, you can check the value of navigator.appVersion for that information. You can experience both types of scripted site entry checks at work at the Urban Oasis Web site. A script checks for both the Navigator 3.0 browser and ShockWave.

MULTIFUNCTION LINKS

You can always interlace a script within a page's HTML to document.write() a link (or any other feature for that matter) that you want only JavaScript-enabled browsers to see. But if you want a single link to be able to branch to one of two possible destinations based on the scripting ability of the browser, you can use JavaScript to help out.

For this technique, create the link to the non-JavaScript destination as follows (as you normally would):

<A HREF="nonJSCatalog.html">Product Catalog</A>

To force this link to navigate to a JavaScript-enabled page, you need to add a special enhancement to the onClick= event handler for this link: return false. Just as a form's onSubmit= event handler cancels the submission of the form if its final statement evaluates to return false, so, too, does a link ignore the HREF attribute if the onClick= event handler ends that way. Therefore, to add the JavaScript destination to the link, use the following code:

<A HREF="nonJSCatalog.html" onClick="location='JSCatalog.html';return
false">Product Catalog</A> 

Without the return false statement, the visitor will end up at the HREF attribute's location. You can still add onMouseOver= and onMouseOut= event handlers to the link to show friendly status bar descriptions of the link for JavaScript-enabled browsers.

SCRIPT EXECUTION

Since only a JavaScript-enabled browser can respond to object event handlers, you can be sure that plain button clicking, select object choosing, and any other user action will be ignored by a non-JavaScript browser. But what about the cases in which you have JavaScript 1.1 features that will cause script errors in JavaScript 1.0-only browsers, such as Navigator 2.0x and the current versions of Microsoft Internet Explorer 3.0? For example, many eager newcomers to JavaScript employ an onMouseOver= and onMouseOut= event handler for an image link to swap the art file associated with the Image object during a mouse rollover. But the Image object is found only in JavaScript 1.1 browsers; any attempt at setting the src property of an Image object in JavaScript 1.0 yields an unfriendly script error.

If you want an event handler to operate differently for JavaScript 1.0 and 1.1, you can create two separate <SCRIPT> segments in your document with identically-named functions that are called by the event handler. One <SCRIPT> tag specifies LANGUAGE="JavaScript" while the other specifies LANGUAGE="JavaScript1.1". The key here, however, is to make sure that the JavaScript 1.1 tag set is lower in the document than its corresponding JavaScript 1.0 version, as shown in Example 2.


Example 2

<HTML> 
<HEAD> 
   <SCRIPT LANGUAGE="JavaScript"> 
   <!-- 
      function doIt() { 
        // statements for JavaScript 1.0 browsers 
      } 
    //--> 
    </SCRIPT> 
    <SCRIPT LANGUAGE="JavaScript1.1"> 
    <!-- 
       function doIt() { 
         // statements for JavaScript 1.1 browsers 
       }
     //--> 
     </SCRIPT> 
</HEAD> 
<BODY> 
<FORM> 
    <INPUT TYPE=button VALUE="Click Me" onClick="doIt()"> 
</FORM> 
</BODY> 
</HTML>


Similarly, you can mask JavaScript 1.0-level browsers in the LANGUAGE="JavaScript" segment by leaving the statements in the function blank or by displaying an alert for the user about what extra functionality a JavaScript 1.1-level browser brings to the user experience.

Another possibility is to use the JavaScript 1.1 feature that lets you set the event handler property of an object from a script. If you restrict the action of setting the event handler to a JavaScript 1.1 script, then only JavaScript 1.1 browsers will respond to user action, as shown in Example 3.


Example 3

 
<HTML> 
<HEAD> 
    <SCRIPT LANGUAGE="JavaScript1.1"> 
    <!-- 
       function doIt() { 
          // statements for JavaScript 1.1 browsers 
       } 
     //--> 
     </SCRIPT> 
</HEAD> 
<BODY>
<FORM> 
    <INPUT TYPE=button NAME=joeButton VALUE="Click Me"> 
    <SCRIPT LANGUAGE="JavaScript1.1"> 
    <!-- 
       document.forms[0].joeButton.onclick=doIt 
    //-->
    </SCRIPT> 
</FORM> 
</BODY> 
</HTML> 


In Example 3, the button object does not have an explicit event handler in its tag. Instead, the reference to the doIt() function defined earlier in the document is assigned to the onclick property of the button. (The property name for an event handler is always in lower case). The <SCRIPT> tag for this assignment must come after the <INPUT> tag that creates the button to make sure the button object exists before its event handler property can be set. In the document defined in Example 3, only JavaScript 1.1-level browsers respond to user action in any way.

ADDITIVE JAVASCRIPT

If you examine the implementations suggested throughout this article, you might see that I tend to treat JavaScript as an additive feature of a page wherever possible -- rather than rushing ahead to make two completely separate tracks through a site. Creating multiple tracks within a Web site makes the maintenance chore all the more difficult.

Perhaps the ideal situation is a page that functions well on its own without JavaScript. By interlacing some <SCRIPT> tags within the basic HTML of the page and some of the event handler techniques described here, you can script added functionality into the page, rather than having to generate an entirely separate track. Visitors who have the latest browsers have a more interactive and enjoyable experience at your site, and people with older browsers will be none the wiser.

This technique won't work all the time, of course. Some of the areas of my Web site, for example, simply require JavaScript or the user will see next to nothing on the page. But it means that I can keep the need for parallel pages at a minimum, simplifying the maintenance task.

THAT ELUSIVE SCRIPT

While there is no magic property, method, or script that detects JavaScript in a browser, you can indeed use JavaScript to enhance the plain HTML page or navigate to fully scripted pages -- and still accommodate nonscriptable browsers. It may take a little extra thought and planning, but the results will invite a wide audience to your site without your having to "dumb down" your pages to the lowest common denominator.


Author and consultant Danny Goodman's 25th book is the JavaScript Bible, the updated second edition of his bestselling JavaScript Handbook, published by IDG Books. His next title, arriving at the end of February 1997, is The Official Marimba Guide to Bongo, published by Sams.net.


Copyright © 1997 Netscape Communications Corporation