Article
Well-Behaved DHTML: A Case Study
It’s no secret that over the last few years DHTML has been used almost exclusively for evil purposes. Users associate the technology with intrusive advertisements and error-prone pages, while developers associate it with browser detection and hideous hacks.
This assumption is unfortunate. Browser technology has made great advancements over the last couple years. When it’s done right, DHTML can improve the users’ experience of many Webpages. And the hacks that used to be required to make it all work are now practically nonexistent.
When working with modern DHTML, I often reminisce about the old days of Web development, when I first became interested in the technology. Despite my best intentions, many of my first scripts now represent examples of what today’s DHTML coders should avoid -- they rely too heavily on specific browser features and throw errors or degrade improperly when those requirements are not met. They don’t work well with other scripts on the same page, and they sometimes create dependencies upon other technologies.
When I encounter scripts like this, I think of them as badly-behaved. They have the potential to be good; all the tools are there. They simply are not doing what they should.
As I’ve grown as a Web developer, I have come to appreciate the value of well-behaved DHTML. I can always sell a client on the fact that the script will either work, or it will gracefully not work, in any browser. They don’t always appreciate obvious generalizations like practically everyone has DHTML enabled these days quite as much as code that degrades gracefully in situations where it’s not supported.
I’ve also noticed that, when developing this kind of DHTML, I tend to follow the same five-step process over and over again. What follows is an example of using this process to create a very basic DHTML script. Once you understand the principles, you can apply this process to most DHTML effects with repeatedly impressive results.
The code examples provided here do assume you have some familiarity with JavaScript, HTML, and the DOM. However, any Web developer or designer should be able to get some value out of familiarity with this process.
The Labels Script
A common use of DHTML on the Web is to create what I’ll call a Dynamic Label. A Dynamic Label is used to label a form field. However, the text for the label is rendered inside the form field, instead of adjacent to it (which would be more usual).
When the form field receives attention, the label disappears so that the user may type. If the user does not type anything, the label is restored as soon as the user clicks or tabs away from the field.
Dynamic labels save space, look sharp, and feel slick. They can be a nice improvement over a basic form label in the right situations.
A naïve developer might implement a dynamic label script like this:
<input type="text" name="username" value="username"
onfocus="if (this.value == 'username') this.value = '';"
onblur="if (this.value == '') this.value = 'username';" />
Example A displays this type of implementation.
It's a valid first step, but that’s all. DHTML like this is an example of the badly designed scripts of yesteryear and should never make it into any production Website.
Let's look at the problems one by one:
- Relies on JavaScript
The effect does not work if JavaScript is disabled. In this case, the label will still actually show up because it was hard-coded into the value attribute of the field. However, when the user focuses the form nothing happens. The user experience is badly broken—probably worse than it would be if there had simply been a normal textual label beside the field.
- Couples to the code that processes the form
Coupling is a term used in programming circles to indicate when two components’ implementations are tied tightly together -- usually a very bad thing. Coupling means that when one component’s code changes, the other component’s code might also have to change.
In our case, the JavaScript that creates our effect is tightly coupled to the server code that processes the forms. The server code must be aware of what the labels are for each form field and be able to filter them out of the form submission. This is because we have put the label’s text in the value attribute of each field. If the user does not type anything into one (or any) of these fields, the label will actually be submitted instead.
To see an example of this in action, just click Submit without typing anything into Example A.
- Exclusively binds to event handlers
A common hitch among novice DHTML scripts is that they set the values of elements’ event properties directly. You can do this through attributes of an element, or in JavaScript with properties. Directly setting JavaScript events is generally a bad idea because only one block of code can use each event. If you start to run more than one script on a page, the various scripts’ event handlers can overwrite each other. This type of DHTML is harder to maintain and can result in errors that are difficult to debug.
In modern browsers, we can use Event Listeners to bind more than one function to a specific event. Avoid the old style of event handling except when it’s absolutely required.
- Non-modular design
This script is not modularly designed. If we decide to implement another dynamic label, we have no choice but to copy and paste our current code into that box’s event handlers and change the various places the label text shows up.
If we discover a bug in the script, or want to make a change, we have to remember to make the changes for each label. If we decide to change the label text, we have to change it in three places. Non-modularly designed programs are difficult to maintain and develop because they are so error-prone. It’s easy to make mistakes and hard to debug them.
Now that we’ve analyzed the problems in our first dynamic labels script, we have a good idea of what our goals should be in the script’s next iteration. In short, we want a dynamic label script that:
- Does not rely on JavaScript
- Does not couple with any other component
- Does not exclusively bind to any events
- Is modularly designed
Aaron is a Web developer living in New York City with his girlfriend,