advanced dom scripting dynamic web design techniques Part One DOM SCRIPTING IN DETAIL CHAPTER 1 DO IT RIGHT WITH BEST PRACTICES

You’re excited; your client is excited. All is well. You’ve just launched the client’s latest website, and it’s fantastic. You’ve put in hours of sweat and tears, tweaking every little detail of the design—expanding menus, interactive Ajax, all the latest bells and whistles. It looks good, works perfectly, and everyone’s partying. But a week later disaster begins. The client phones in a panic; it seems they’ve been getting calls from some customers who can’t get past the home page, and others are having problems with some aspects of the feedback form—but it works fine for you and the client. Other people have been calling and complaining that the site is taking too long to download each page, even though it doesn’t look like there’s much on the page, and you barely notice the load time. To top it off, the client has found that its search engine ranking has plummeted from number one to nowhere. Things are not good after all. But where could you have gone wrong? Let’s find out.

Best practices are accepted and tested models for the way you should go about doing things. They’re not necessarily the only way or even the best way, but they’re the way the majority agrees things should be done. Most of the time, best practices are mentioned near the end of a book, more as a reminder that once you’ve learned everything and you’re on your way, there’s actually a proper way to do it. I’m putting best practices up front, because I want to guide you in the right direction before you learn anything new. There’s no point in going down dark roads of frustration when there’s already a well-lit road ahead.

Unobtrusive and progressive enhancement

Extensible HyperText Markup Language (XHTML), Cascading Style Sheets (CSS), and Document Object Model (DOM) scripting using JavaScript are the big three of web design. XHTML provides the semantic meaning in your document structure; CSS provides the positioning and style for your document layout; and DOM Scripting enhances your document’s behavior and interaction. Did you catch that? I said DOM scripting enhances, not provides, your document’s behavior and interaction. The difference between “enhances” and “provides” is an important distinction. We’ve all learned about XHTML,semantics, and validating our documents so they conform to the W3C specifications, and we all use CSS to properly style our semantically marked up XHTML strict documents (you do, don’t you?), but DOM scripting, the third piece, the one that makes things extra slick and gives your web applications extra flare, can be an obtrusive beast.

DOM scripting relies on JavaScript. If you search for “Unobtrusive JavaScript” on the Web, you’ll find a flood of different descriptions, but that’s only because unobtrusiveness needs to be considered everywhere. It’s not a Band-Aid you can just throw onto your code to make it all good. There’s no unobtrusive object in JavaScript (Hmm . . . maybe there could be?), and you can’t download some “unobtrusive” library to fix your code. Unobtrusiveness is only possible with proper planning and preparation in your web application. It must be considered when interacting with both the user and the web developer. Your scripts must be unobtrusive to the user and avoid unnecessary flashy and annoying features (something that gave JavaScript a bad rap in the past). Scripts must also be unobtrusive to allow the page and markup to continue to work, though maybe not as elegantly, without JavaScript. Finally, they must be  unobtrusive and easy to implement within your markup, using ID and class hooks to attach behavior and provide a separation of the script from the markup. To better understand unobtrusiveness, and the integration of DOM scripting, XHTML, and CSS, you need to consider the outcomes in the situation we looked at previously and understand the basic principles and
their application to your code.

Two methodologies you often hear about with unobtrusiveness are “progressive enhancement” and “graceful degradation.” Browsers that lack certain features should receive an equally informational,yet altered, view of the same document by using techniques that either enhance the document as technologies are available (progressive enhancement) or degrade the document when they are missing (graceful degradation). These two concepts are often used interchangeably, but each embraces the idea that not all browsers are created equal—and not all browsers should be treated equally. Also, you shouldn’t force a low quality service on everyone just to be able to cater to the lowest common denominator.

One of my favorite quotes about the necessity of progressive enhancement comes from Nate Koechley of Yahoo, who sums it up when describing browser support  (http://developer.yahoo.com/yui/articles/gbs/gbs.html):

 

“Support does not mean that everybody gets the same thing. Expecting two users using different browser software to have the identical experience fails to embrace or acknowledge the heterogeneous essence of the Web. In fact, requiring the same experience for all users creates a barrier to participation. Availability and accessibility of content should be our key priority.”

If you’re using JavaScript in a way that inhibits the “availability and accessibility of content,” you’re doing something wrong.

At the same time, progressive enhancement doesn’t necessarily mean an all-or-nothing approach to JavaScript. The problem is that, unlike most programming or scripting languages that you would run on your own dedicated servers or computers, JavaScript is an interpreted language that runs within a web browser, so you won’t have any control over the wide variety and mix of software, hardware, and operating systems your script will need to handle. To deal with the infinite combinations, you have to be careful and create behavioral enhancements based on the capabilities of the browser and the available technologies, which could mean providing a degraded solution that still relies on lesser parts of JavaScript or a solution that falls back on traditional, JavaScript-free methods.

I’ll be stressing these ideas of unobtrusiveness, degradability, and progressive enhancement throughout the book, but I’ll also say that I am by no means a zealot. I do realize that your sites do need to support browsers without standards-compliant features. In many cases, proprietary methods will also be required, but the trick is to go for the standards-compliant way and only fall back on the proprietary way if necessary.

When working with DOM scripts and integrating them into your site, you should always write scripts that are 

Standards compliant:Future-proof your application and ensure that your web application will continue to support newer and better browsers.

Maintainable: Incorporate reusable and easily understood methods so that you and others can focus on the business task at hand, rather than rewriting the same things over and over.
Accessible: Ensure that everyone can easily and efficiently access your information, even those without the script or JavaScript enabled.
Usable: Something that works great in one situation but is hard to implement or replicate isn’t going to be much fun the second or third time around. Usability applies to both the interaction
with the end user and the interaction with developers.

These guiding principles overlap in practice, and they all go hand in hand; keeping them in the front of your mind will go a long way to reducing headaches now and down the road. In fact, I suggest posting them on a big, bold sign next to your computer, so you can drill them into your head. I’ll even pro-
vide you with a printable sign at http://advanceddomscripting.com/remember.pdf. Just remember, if the goal of XHTML and CSS is to be universally standard, your JavaScript scripts should be too!

In the rest of this chapter, you’ll look at several methods that will help you achieve these goals and keep your clients, coworkers, and yourself as happy as possible. Also, you’ll start building up your own library of common methods that you’ll use throughout the book while looking at some common JavaScript gotchas.

Putting JavaScript to work

So where do you start? What will make your hard work fit the guiding principles?
Odds are if you were to look at the failed hypothetical site at the beginning of the chapter, you’d probably see some common pitfalls like these:

<script> tags inline within the body of the document
A reliance on browser sniffing rather than capability detection to test for JavaScript feature compatibility
Hard-coded javascript: prefixes in the href attributes of anchor elements
Redundant, repetitive, highly customized JavaScript

 

 

 

You might wonder what the problem is with these. After all, we’ve all used at least one quick-and-dirty hack at one time or another. The problem is really in their usefulness and inability to accommodate all situations. If you step back and look at each item critically, you’ll realize it doesn’t take much more effort to do it the right way—and you’ll get additional benefits. To help you avoid these and many other mistakes, let’s look at the general ideas behind the problems and what you should remember when implementing your next site.

 

Separating your behavior from your structure

The number one thing you can do to improve any project involving JavaScript is to separate your behavior from your markup. This key technique is often overlooked or not given enough attention.Following the same design rule of separating CSS from the XHTML documents using external style sheets, your JavaScript should also separate itself into external files. With CSS, you could use the style attribute on tags to apply CSS to your DOM objects, but that’s not any more maintainable than an old school mess of <font> tags. Why, then, does it happen so often that a beautifully designed site will mark up the XHTML with id and class selectors, nicely separate out all the CSS into an external file,but then throw a whole mess of inline JavaScript into the document? This must be stopped now!JavaScript should follow the same separation rules as CSS.

How to include JavaScript the right way

There are several different ways you can add JavaScript to your web applications. You’ve probably seen or used all of them, but not all of them are good. I hesitate to show you these methods as I don’t want to corrupt you right from the start, but just so we’re on the same page, I’ll go through each method and point out a few problems.

First, you could add your script embedded between the body tags mixed in with your other markup:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Inline JavaScript</title>
</head>
<body>
<h1>Inline Example</h1>
<script type="text/javascript">
//JavaScript Code
</script>
</body>
</html>

But that doesn’t provide any sort of separation between your behavioral enhancements and your structured markup. It opens up your code to repetitive and often unnecessary code replication as well.

Savvy readers may notice I didn’t add any of the typical commenting tags—<!-- and //--> or <!--//--><![CDATA[//><!-- and //--><!]]>—within the script tags to hide the JavaScript from very old browsers or XML parsers. If you’ve been using JavaScript inline in the <body> of the document, you can join the comment versus no-comments debate, or you can take my advice and ignore inline scripts altogether. Therefore, I’m not going to overcomplicate this information by explaining the comment tags.

The only time inline JavaScript may be useful is if you want to use the document.write() method to directly modify the page at that point. However, there are better solutions to accomplish the same task, as you’ll see later.
Next, you could add your script embedded in the <head> of the document:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Head JavaScript</title>
<script type="text/javascript">
//JavaScript Code
</script>
</head>
<body>
<h1>Head Example</h1>
</body>
</html>

This is arguably better. At least it assembles all the code into an appropriate location within the markup, but it’s still mixing the structure and behavior, just on a lesser scale.

 

Finally, you could include it from an external source file:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>External File JavaScript</title>
<script type="text/javascript" src="source.js"></script>
</head>
<body>
<h1>External File Example</h1>
</body>
</html>

This is always the correct and best method. As a general rule, most people say that any script that doesn’t directly write out to the document (using the document.write() method) should be placed in the <head> of the markup. While this is true, I say take it one step further. No matter what—yes, that’s right; no matter what—use an external source file to include all your scripts. Pretend you never saw the first two methods. In fact, pretend they don’t exist. If there’s any JavaScript in your markup, you should go back and remove it to create a clean separation of behavior and structure. There’s no situation where you can’t put all your code in a source file, and doing so offers a lot of advantages. You’ll be forced to rethink how you go about creating your functions and objects: are you keeping things simple and maintainable by creating reusable, generic code, or are you overcomplicating things by creating custom copies of the same logic? External files also offer the advantage of reducing the overall page size. They’ll usually be cached by the client’s web browser and only downloaded once, reducing the load time of each following page.

 

 

 

The only real difference you may have to overcome is that your beloved document.write() method may not work as expected. However, since this is a DOM scripting book, and we want to use the generic, browser-agnostic DOM methods, you’d be better off using the createElement() and appendChild() DOM methods or the unofficial innerHTML property—but we’ll discuss that later.

That javascript: prefix

You may notice I missed a few additional places where JavaScript may crop up in your document,specifically in the attributes of elements. Consider the case of opening a new pop-up window. If you’re using a strict DOCTYPE specification, the target attribute of the anchor tag is not valid:

<a href="http://advanceddomscripting.com" target="_blank">å
AdvancED DOM Scripting</a>

so the only valid way to open another window is with JavaScript. In these cases, you’ve probably used,or at least come across, JavaScript in the <a> tags href attribute using the special javascript: prefix:

<a href="javascript:window.open('http://advanceddomscripting.com');">
AdvancED DOM Scripting</a>

But in this case, you won’t get the results you’re looking for.

To test these inline examples yourself, see the example page included in the source for this book at chapter1/popup/examples.html or on this book’s website at http://
advanceddomscripting.com.

One problem with the javascript: prefix is that it can handle only one function, nothing more. And if that function returns a value, the initial page may be overwritten with the result. For example, clicking the previous anchor with javascript:window.open(...) in Firefox opens the new window as expected, but the original window is overwritten with the result of the  window.open() method, [object Window], as shown in Figure 1-1.

This problem, however, can be overcome by including an additional function in a script:

function popup(url) {
window.open(url);
//do not return anything!
}

and referencing it rather than directly referencing window.open:

<a href="javascript:popup('http://advanceddomscripting.com');">
AdvancED DOM Scripting</a> 

That’s still using the inline javascript: prefix. To avoid the need for the wrapper function, you may have tried to be a little less obtrusive by attaching your JavaScript to elements using the onclick event attribute to directly open the URL and simply placing a # in the href attribute:

<a href="#" onclick="window.open('http://advanceddomscripting.com');">
AdvancED DOM Scripting</a>

The onclick event attribute is a little better, but neither of these methods, when coded directly into your document, offers any separation of behavior and structure nor are they unobtrusive: Using the special javascript: prefix in href attributes is problematic, as it’s not part of the official ECMAScript standard (http://www.ecma-international.org/publications/standards/Ecma-262.htm), but it’s generally implemented by all browsers supporting ECMAScript. Using the prefix, or the previous onclick attribute, creates a direct reliance on JavaScript to navigate or activate the anchor.

Since neither option is perfect, the best solution is to at least use the inline event attribute to alter or use the existing attributes, such as the URL in the href. The previous two anchor examples could be rewritten to alter the existing href value, so when JavaScript is disabled, the anchor would still work as expected:

<a href="http://advanceddomscripting.com" onclick="this.href=
'javascript:popup(\'http://advanceddomscripting.com\');'"
AdvancED DOM Scripting</a>

An even better solution would be to retrieve the value of the href attribute from within the onclick event attribute:

<a href="http://advanceddomscripting.com" onclick="popup(this.href);
return false;">AdvancED DOM Scripting</a>

When a regular <a> link is clicked, the browser normally executes the default action of the anchor,which is to follow the href to wherever the path goes. However, when dealing with interactions such as clicks, the onclick event attribute must execute first; otherwise, the browsers would have already navigated to its new location before onclick had a chance to do its thing and that action would be lost.

Let’s look at the first rewritten case where you use the javascript: prefix and the popup() function in the onclick attribute:

<a href="http://advanceddomscripting.com" onclick="this.href=
'javascript:popup(\'http://advanceddomscripting.com\');'">
AdvancED DOM Scripting</a>

Running this script results in the following actions:
1. Your onclick event occurs, changing the href attribute value of the link to href="javascript:popup('http://advanceddomscripting.com');" which uses the javascript: prefix to execute the earlier popup() function included elsewhere in the document.
2. The anchor’s default action, following the href, is executed using the new value, which, in turn,executes the pop-up function and opens the desired URL.

By using the onclick attribute in this way, you’re achieving the same result you would have by simply using the javascript: prefix, but the anchor will still function when JavaScript is disabled.Now let’s look at the second rewritten case where you use the popup() function by referencing the href value of the anchor in the onclick attribute:

<a href="http://advanceddomscripting.com" onclick="popup(this.href);
return false;">AdvancED DOM Scripting</a>

Here’s what happens in this case:
1. Your onclick event occurs, executing the same popup() function (or window.open() directly):
popup('http://advanceddomscripting.com');
2. But you must also return false to prevent the default action.

When you return false from the inline onclick event attribute, you’re telling the browser to stop and ignore the rest of the events in the chain, including the default action. In this case, the browser stops execution of the default action and doesn’t follow the link in the href attribute.

 

posted @ 2014-10-05 13:28  wuhn  阅读(263)  评论(0编辑  收藏  举报