HTML enables you to take plain text and turn it into an attractively laid out document. It also lets you turn the text into an ugly mess that no one would want to read. JavaScript confers an even greater ability to create a spectacular document, and an even greater ability to create a hideous page that no one will want to read. Using JavaScript, you can even crash the browser. This chapter explains how to use JavaScript judiciously so your Web pages both look nice and run smoothly.
Your Web pages are your personal ambassadors to the world. They make a statement about you. Naturally, you can't control everyone's reaction to your pages; some people simply are not going to take an interest in what you have to say. But you can take simple steps in terms of the content of your pages (what you say) and in terms of the presentation of your pages (how you say it) to maximize the impact you want your pages to have.
What you say and how you say it makes a big difference in how readers view your pages. Simple mistakes in the content-particularly the text portions of your page-can lose readers or make a poor impression, and such mistakes are not that difficult to prevent.
"Speling"? That really looks bad, doesn't it? If you're writing the text in your pages in your native language (people tend to cut you some slack otherwise), check your spelling. Misspelled words convey a bad impression, making you look sloppy, careless, ignorant-take your pick. If you make spelling mistakes, the best you can hope for is that your readers don't notice or don't care.
So check the spelling in your pages before you load them onto your server for public consumption. Most word processors have built-in or bundled spell checking capabilities. Most of them can learn to accept and ignore HTML tags. Some online services will check the spelling of your pages within seconds; these services already know to overlook HTML tags.
If you have a lot of JavaScript code in your pages, the spell checker will probably go ballistic over the code. It will not recognize your variable or function names unless you've entered them into the spell checker's dictionary, which is a practice I do not endorse. (It tends to clutter up the dictionary, and unless you're using the spell checker strictly for your Web pages, you've just told the spell checker to ignore what may well be typos in a business letter.) The solution is to make a copy of your page and remove the contents of the <SCRIPT> element before running the copy through a spell checker. Because you'll be making changes by hand, this should be an iterative process (you'll repeat these steps until the text of your page is clean). Of course, you can avoid the iterative process if you have access to software that will merge changes automatically. Here is what you should do:
Sometimes you may want to deliberately use misspelled words, as in the heading of this section. As long as the typical reader will realize that the word is deliberately misspelled, this is probably not a problem.
You may also use misspelled words in quotations that contain misspellings. To handle this situation, first enclose the quotation within an appropriate element, such as <CITE>, so the reader has a clue that the enclosed text is a quotation. Second, you may want to place the Latin word "sic" in parentheses following the misspelled word. This tells your readers that you are quoting a misspelled word rather than misspelling the word yourself.
Unless you want your readers to instantly consider you an adolescent who finally cracked mommy or daddy's password, avoid misspellings such as "kewl" and "dood" and "warez." Also try to remember the difference between the letter "O" and the number "0." They are not interchangeable.
Poor grammar can alienate your readers as much as poor spelling can. Unfortunately, it's a little bit more difficult to check grammar than it is to check spelling. Grammar checking software is less common than spell checking software. Grammar also includes many gray areas, and grammar checking
software is more likely than spell checking software to miss errors and falsely label valid text as erroneous. However, few readers will recognize subtle errors, and the rules of grammar often allow for exceptions.
A good approach is to try to catch the big errors. Don't mix up singular and plural in the subject and predicate of a sentence. An old rock standard from the early '60s contains a line, "I knew we was falling in love," that has the same effect on me as fingernails on a chalkboard. Although that particular error may not bother you, it really stands out in print. Don't confuse possessive words with contractions that involve the word "is," especially "its" (which means belonging to or pertaining to "it") and "it's" (which means "it is"). Dust off a copy of Strunk and White's Elements of Style, or check it out on the Web.
Adults built the World Wide Web for adults. It was never intended to be a medium for children. Nevertheless, it has become a medium that children can and do use.
Does this mean that your pages should be free of content that may not be appropriate for children? Personally, I don't think that's necessary. I don't carry this kind of material in my own pages, primarily because it attracts a lot of hits. I have no compelling reason to degrade my Web space provider's performance or to pay extra for the privilege of doing so.
Still, you may choose to include such material on your page. If you do, it is a common courtesy to have a "gatekeeper" page warning readers that they're about to access material that may not be appropriate for children.
After going through the gatekeeper page, the reader has the protected page's URL. At this point, the reader can bookmark the URL or publish the URL to others, who can then bypass the gatekeeper and go straight to the protected page. JavaScript provides a mechanism for ensuring that readers go through your gatekeeper first: the document object's referrer property.
The referrer property provides you with a read-only string containing the full URL of the page that the reader just came from. When your page is loaded, it can check the referrer property to see if the reader loaded this page from the gatekeeper page and refuse to load the restricted contents. Here's a sample gatekeeper page, referrer.htm:
<HTML> <HEAD> <TITLE>Gatekeeper</TITLE> </HEAD> <BODY> <A HREF="protect.htm">Click here</A> </BODY> </HTML>
This very simple page's sole purpose is to provide access to the adult material in protect.htm.
Here's protect.htm:
<HTML> <HEAD> <TITLE>Protected Material</TITLE> <SCRIPT> <!-- beginning of script if (document.referrer != "file:///C|/JVSCRIPT.MOS/REFERRER.HTM") { history.back(); } else { // we got here from the correct URL } // end of script --> </SCRIPT> </HEAD> <BODY> <!-- protected material goes here --> </BODY> </HTML>
This protection is very simple: If the referrer property doesn't match the URL of the gatekeeper page, the browser bounces the reader straight back to where he or she came from. You could enhance this protection scheme by using the alert() method to display a message to the reader, explaining that he or she cannot access this page directly, but must first pass through the gatekeeper page.
To get the URL of the referring page, I originally included code in protect.htm that wrote the contents of the referrer property to the page:
document.write(document.referrer);
If I placed these pages on my Web space provider, I would comment out the history.back() call and reintroduce the document.write(document.referrer) call. By doing so, I make sure I have the correct format for referrer.htm's URL.
The best content in the world is useless if you're the only one who can see it. It's easy to forget that not everyone is using a system exactly like yours. Even if your system presents your page the way you want it to, not everyone else will necessarily see what you want them to see.
It's a sad but true fact that not all browsers support JavaScript. Readers using popular browsers such as NCSA Mosaic will not benefit from your JavaScript expertise. Unless you want to alienate those readers, you need to be sensitive to the needs of the Netscape-deficient. Two major errors to avoid are littering the screen with JavaScript code and leaving a blank page for the reader to ponder.
Hide your code The casual reader is probably not interested in your Java-Script code. The reader using a browser that can't interpret JavaScript code is even less likely to be interested in it. Hide your code. Embedding JavaScript within comment tags is an important step in hiding the code. Browsers that don't support JavaScript will display the JavaScript code that lies within the <SCRIPT> element as plain text. If you place this code within comment tags it won't be displayed. Immediately following the <SCRIPT> tag, insert the beginning of an HTML comment (<!--). Netscape will ignore it; other browsers will see that it is the start of a comment.
Just before the </SCRIPT> tag, you need to end the comment. There are two ways you can do this; you can use the method you prefer.
The first way of ending a comment is to place a complete HTML comment at the end of the JavaScript code, like this:
<!-- end of script --></SCRIPT>
To Netscape, this looks like a new comment followed by the </SCRIPT> end tag. Other browsers ignore the <!-- and see the --> as the end of the comment that was started at the beginning of the <SCRIPT> element.
The other way of ending a comment is to begin a JavaScript one-line comment-the kind that starts with // and ends with the end of the source line. Just make sure that the --> is at the end of the comment. As with the first method, browsers that don't support JavaScript will close the comment that was begun after the <SCRIPT> tag when they see the --> at the end of the comment. Netscape sees it as a routine JavaScript comment. The only drawback to this technique is that it forces the </SCRIPT> tag to be on the next source line. If it were on the same line as the one-line comment, it would become part of the comment.
It's easy to hide your JavaScript code. However, your own code could sabotage your efforts to make it invisible. Here are two steps to take to prevent this unwitting sabotage:
First, don't use the decrement operator (--). Some browsers see the double hyphen as the end of the comment; everything following the decrement operator may show up on the reader's screen. Instead, use the -= operator with an operand of 1, like this:
x -= 1;
Second, avoid using the > character in your script. Some browsers treat the > character as the end of the comment regardless of whether it's preceded by --.
The > symbol will show up in your JavaScript code as the greater than operator and as the end of tags. The first usage is trivial to fix; instead of
x > y
rewrite your code as:
y < x
The two expressions are identical in their value: true if x is greater than y and false if x is less than or equal to y.
The second usage is a little harder to fix. Suppose you write a tag like this:
document.write("<TITLE>Visible code under some browsers</TITLE>");
First, you need to create a string that contains a single > character, like this:
var tagEnd = unescape("%3E");
Then, in subsequent lines, substitute your string as needed, like this:
document.write("<TITLE" + tagEnd + "Invisible code under all browsers</TITLE" + tagEnd);
Try to see your document their way When creating Web pages, it's important to know how they'll look to others. You can download many of the major browsers, such as Mosaic, for your favorite platform and purchase costs are not very high. Get the major browsers and load your pages into them so you can get a sense of how your pages will look to your readers.
Don't forget to use the <NOFRAME> element if your pages use frames. This element allows you to include text that frame-ignorant browsers will display. The text can be as elaborate as a full HTML 2.0 compliant <BODY> element, or it can be as simple as an explanation like this:
<NOFRAME> We are sorry to inform you that you have accessed a page that you need Netscape 2.0 to fully appreciate. You are not using Netscape 2.0; if you were, you wouldn't see this text. <A HREF="your HTML 2.0 version of this page">Here</A> is an equivalent page that doesn't require Netscape. Perhaps you should consider downloading a copy of <A HREF="Netscape's URL for downloading the latest version of Netscape Navigator">Netscape Navigator</A>. </NOFRAME>
Finally, some browsers, such as lynx, don't know what to do with images. Don't forget to include the ALT attribute in all of your inline images; it lets you define alternate text that can be displayed in lieu of your image.
Not all platforms support 24-bit color in a 1280x1024 screen resolution. If you create a page that relies on having lots of screen real estate and thousands of colors, you will disappoint a lot of readers. Of all the platforms that support the Netscape Navigator, the title of "least forgiving" probably has to go to Windows 3.1, running in 640x480 pixel mode, using 16 colors.
Recall that colors are expressed as a red-green-blue triplet, with 8 bits per component. That's 24 bits. That's wonderful for people with state-of-the-art video, and it's not too bad even for people whose systems can only eke out 8 bits (256 colors). But for video that is restricted to 4 bits for color, it's a challenge. How many colors are you using? Before you answer that, don't forget the colors in your inline GIF and JPEG images. Try out your page on a 16-color system. How does it look? More importantly, can you read it?
Okay, maybe you don't care about those cheapskates who can't be bothered to upgrade their systems with a decent video card and monitor. After all, prices are dropping. What's the problem?
Well, you still need to deal with the 640x480 pixel straightjacket, and that's not necessarily an artifact of a low-end system. The better the screen resolution, the smaller the pixels, and the smaller the pixels, the harder it is to read text. A lot of people suffer from a medical condition called presbyopia. If you're pushing 40 or you've passed that milestone, you probably know what this is. It's why you wear reading glasses, or bifocals, or progressive lenses. You can't focus on small print as you used to. The rest of you whippersnappers out there, heh heh, it's waiting for you.
So what does this mean to you as a page author? It means you want to be careful about creating documents with lots of frames subdividing the canvas. If I, the reader, have to squint to see your frame contents, or scroll madly in all directions, I don't care if you have the plans for world peace in your page. I'm not going to go to the trouble of trying to read it! Bottom line: Keep your pages simple. Keep the clutter to a minimum. To test your pages, here's a very simple page I call "The Bed of Procustes":
<HTML> <HEAD> <TITLE>The Bed of Procustes</TITLE> <SCRIPT> <!-- Hide from primitive browsers function putToBed(form) { // get the data from the form... var url = form.urlWidget.value; var width = form.widthWidget.value; var height = form.heightWidget.value; // create the command. specifying the url in the command seems to be // a problem, so the window is created empty, then loaded var command = "window.open('', 'noname',"; command += " 'toolbar=yes,location=yes,directories=yes,status=yes,"; command += "menubar=yes,scrollbars=yes,resizable=no,width=" + width; command += ",height=" + height + "')"; // create the window var bed = eval(command); // do it twice for brain-damaged platforms bed = eval(command); // load it bed.location.href = url; // we're not really submitting a form, so return false return false; } //--> </SCRIPT> </HEAD> <BODY> <FORM ONSUBMIT="putToBed(this)"> Window Width: <INPUT TYPE=TEXT SIZE=5 NAME="widthWidget"> Window Height: <INPUT TYPE=TEXT SIZE=5 NAME="heightWidget"> <BR> URL To Be Loaded: <INPUT TYPE=TEXT SIZE=50 NAME="urlWidget"> <BR> <INPUT TYPE=SUBMIT VALUE="Make it so"> </FORM> </BODY> </HTML>
This page generates a form into which you enter the URL of your page and specify the height and width of the browser. Clicking on the submit button creates a browser window of the specified size. The new browser window has all of the normal buttons and menu items associated with a browser window. After the new window is created, the specified page is loaded into it.
This section explains how to write documents defensively. Readers will-sometimes by accident, sometimes maliciously-try to do things with your document that you did not intend them to do. You'd be surprised how many programmers don't follow these principles. (Okay, you've seen enough bugs; maybe you wouldn't be.)
First, you should make sure your functions are loaded, which is easy to do. If you use a function that isn't loaded, your code will malfunction. What's more, it's almost certain to malfunction in a manner that leaves no doubt in the reader's mind that something went wrong-and that it's your fault. If there are JavaScript expressions in the body of your page and those expressions call other JavaScript functions that you wrote, place those JavaScript functions in a <SCRIPT> element within the <HEAD> element. The <HEAD> element is loaded before the <BODY> element; you can depend on the function being there. This approach prevents a user from impatiently clicking on a partially loaded page and invoking a JavaScript function that hasn't been downloaded from the server yet.
If you're getting input from the reader, make sure you check it before blindly using it, especially if it's supposed to be a number. Use the parseInt() and parseFloat() functions. If it's supposed to be an integer, check it like this:
if (Math.ceil(x) == x) { // it's an integer } else { // oops... }
The Math object's ceil() method returns the next higher integer for a floating-point value; for an integer value, it will return the same value. The floor() method will also work.
Finally, if the number is supposed to be within a certain range of values, make sure that it's within the specifications. For example, if it's supposed to be a value from 1 to 10, put something like this in your code:
if (x < 1 || 1Ø < x) { alert("" + x + "is not between 1 and 1Ø"); return; }
Sometimes users will input data that they're not supposed to. Some users will be confused about what they're supposed to enter; they won't understand what they're supposed to do. Other users will deliberately try to make your page crash just for fun. Assume that when you ask for a number, someone is going to enter anything except a number. "But you're not supposed to do that" is not a valid defense for letting your code malfunction just because you asked for a number but someone entered a phone number or the word "no."
There are some differences between the implementations of Netscape Navigator for the various supported platforms. You can't expect everyone to use the same platform that you use, and you should write your code to defend against problems tied to specific platforms:
Either use the navigator object's appVersion property to find out what platform your JavaScript code is running on and adjust the runtime behavior of your code accordingly, or include workarounds for known differences between the platforms.
Nearly all Web pages are living documents. Someone has to maintain them, and there's no guarantee that the person who wrote the original document will always be around to explain how it works. For that matter, there's no guarantee that the original author will remember how it works six months later. Fortunately, there are several simple strategies for making your documents easy to understand and maintain.
Use comments. For every function, explain what the parameters are and what they're used for. Explain what the function does and what it does if the inputs aren't entered correctly. Within the function body, explain what each functional block does, how it does it, and why it does it. Some people use a standard comment block for each function, like this:
// // function name: (name of function) // author: (author of function) // revision history: (what was changed, when, and why?) // parameters: (what are the parameters, what do they // represent, what kind of values should they contain?) // returns: (does the function return a value? What kind // of value? What does the value mean?) // purpose: (what does this function do?) // global variables used: (useful in debugging to figure // out who touched the contents) //
Write down your assumptions. Do certain named objects have to exist for the code to work? Say so!
Using comments to document your code helps you in two ways: First, it helps indicate what you were thinking when you wrote the function. That information will be invaluable later when you need to modify the function or use it in another page.
Second, the act of documenting your code forces you to think about what it does and how it does it. Often, you'll realize that there is a better, faster, more reliable way to do what you're doing, and you'll improve your code.
When modifying code, make sure that your comments are still accurate. There is not much worse than comments that are no longer accurate and that now lead you astray.
There are many ways to write JavaScript. The browser doesn't care what the code looks like, as long as it can tell what you're doing. You need to select a JavaScript style that works for you and that helps you visualize what's going on. Although you have a lot of leeway, it's critical to be consistent.
Here are some general pointers:
The last rule is to have fun. JavaScript should make it fun to make your pages more exciting and attractive. Don't make it drudgery!