Dan's Web Tips | Graceful Degradation

Dan's Web Tips:

Graceful Degradation

[<== Previous] | [Up] | [Next ==>]

Italian translation provided by Earth Moon
Dutch translation provided by WorldLiterate
French translation provided by Kate Bondareva
German translation provided by André Lungstraß
Hungarian translation provided by Zsolt Boros
Lithuanian translation provided by Giedrius Sadauskas
Mongolian translation provided by Batar Ulanov
Spanish translation provided by 7 Binary Options

TIP: There's nothing wrong with using all the latest bells and whistles to support snazzy features of newer browsers, but try to do it in a way that still allows users not supporting (or intentionally disabling) these features to access your basic content. Fortunately, this is easy to do on the Web, if you follow the spirit of the languages and protocols instead of fighting it.

"Graceful Degradation" is an important principle in Web design. It means that, when you put in features designed to take advantage of the latest and greatest features of newer browsers, you should do it in a way that older browsers, and browsers letting users disable particular features, can "step down" to a method that still allows access to the basic content of the site, though perhaps not as snazzy in appearance.

Nearly every new feature added to the Web has been done in a way that allows graceful degradation, starting with the addition of the <IMG> tag to add graphics to a formerly all-text Web, which contains an ALT attribute allowing you to provide a text alternative for nongraphical browsers.

NOTE: It would have been even more graceful if the IMG tag had been defined as a container element, with the alternative content in between <IMG> and </IMG>. This would have caused the alternative content to be used automatically in older browsers that didn't understand IMG, as well as permitting this content to include markup tags, something that isn't possible in the ALT attribute. But this is now water under the bridge.

Newer constructs like <APPLET> and <OBJECT> let you provide graceful degradation through the use of alternative content between the opening and closing tags of the element. Anything between <APPLET> and </APPLET> (other than the parameters of the applet itself) will be ignored by a Java-supporting browser with Java enabled, but will be used in place of the applet by a browser that doesn't understand Java or has disabled it. This lets the site developer provide alternative static pictures, text, or links to replace the information presented in applet form to users supporting it.

Here's an example of an applet coded for graceful degradation:

<APPLET CODE="WaveEffect" align=center border=0 codebase="http://www.example.net/applets/" width=200 height=200">
<PARAM NAME=image VALUE="enternow.gif">
<PARAM NAME=HREF VALUE="home.html">
<A HREF="home.html"><IMG SRC="enternow.gif" width=200 height=200 alt="Enter my site now."></A>
</APPLET>

A Java-supporting user will see the result of an applet "WaveEffect", which presumably would show a graphic with animated wave effects, and provide a way of getting to the linked URL provided in the "HREF" parameter. But a non-Java user would have no way of seeing what was supposed to be there, or getting onward into the site if this was the only navigational technique, except for the alternative content. This content consists of a normal static IMG tag presenting the same graphic in a non-animated manner, hyperlinked to the same page the applet would let the user go to. And, in the case of text browsers, yet another level of graceful degradation is provided by the ALT text with the image.

In some cases, when there are several different ways of doing the same effect, and the set of browsers supporting one or another of them is slightly different, you can achieve the maximum compatibility by having several levels of nested contstructs that can be gracefully degraded, like an APPLET within an EMBED within an OBJECT.

There are also a few special tags that let you include content that is only used when specific features are unavailable or disabled. For instance, NOSCRIPT elements display only when JavaScript is unsupported or disabled. This can be useful for providing alternative navigation in sites where the main controls are implemented in JavaScript. Similarly, NOEMBED elements are used only when EMBED is not supported.

It takes only a little bit more work to do this correctly, and adds greatly to the accessibility, flexibility, and search-engine indexability of your pages.

Gracefully Degrading JavaScript Popups

A common effect used on many pages is a linked document that comes up as a small JavaScript-created popup window. If you use this effect, it should be sparingly if at all, since it can be annoying to many users. However, there are occasions where it's useful, such as in popping up reference material to assist somebody in filling out a Web form, without their having to leave the page with the form (and possibly not be able to get back to it if it expires from their cache, losing the data they've partially entered).

Often, developers will do this with a javascript: URL. This leaves a lot to be desired in terms of graceful degradation, since non-JavaScript-enabled browsers won't know what to do with such a link at all, and will either do nothing or produce an error. Also, javascript: URLs aren't really standards-compliant; I don't know of any formal specs for this construct, and they often contain characters not legal to include (unescaped) in URLs according to the specs (like spaces).

Fortunately, there's a better way. Instead of <A HREF="javascript:YourPopupFunction('somefile.html')">, use <A HREF="somefile.html" onClick="YourPopupFunction('somefile.html'); return false">. (I assume you've defined the JavaScript function YourPopupFunction somewhere in your document.) The onClick attribute contains code that is executed (on supporting browsers) when the link is clicked, and the ending return false causes the browser to stop after doing this (instead of going on to follow the normal hyperlink). Thus, it has the exact same effect as the javascript: link. (Note that the code in onClick doesn't start with "javascript:", since it's not in the form of an URL.) But for non-JavaScript-enabled browsers, the onClick is ignored and the normal link is followed. So all users get to see the document you're linking to.

NOTE: Since writing the above, I've found out that certain old browsers with early implementations of JavaScript don't support return false correctly and end up doing both the popup and the "plain" link. You can avoid this by using <A HREF="somefile.html" target="somename" onClick="newwin = window.open('', 'somename', 'width=150,height=150,resizable=1');">, which opens an empty window named "somename" and then allows the regular link to target it. Non-JavaScript browsers will simply open a new regular window named "somename", or else ignore the target and open the new page in the original window. However, even more recently, I've found that the Mozilla browser, when configured to ignore attempts to open new windows, will in this case open the popup window but then open the link destination in the original window, leaving the popup window uselessly open. So, all things considered, the previous example code is probably best.

These techniques can also be used in other instances where you wish a link to execute JavaScript code, such as a link mimicing the browser's "Back" button with history.back(). But think carefully about whether you really need to use such a function; users are likely to be confused by links that do things like go back in your history instead of moving forward to another page as links normally do.

TIP: Always use a meaningful HREF attribute in your links, not a "dummy" one, even if the main purpose of the link is to trigger a script.

By all means, don't use the regrettably rampant technique of making hyperlinks go to the "dummy" HREF value of "#"; I'm not sure who invented that, but it seems to have been implemented that way in some authoring tools which generate links with fancy JavaScript, and imitated from there in all sorts of sites, even some that are hand-coded. It's a bad idea -- as I showed you above, you ought to make the hyperlink reference something meaningful which will work even when JavaScript is disabled -- and, furthermore, since "#" is undefined as a URL reference, it's interpreted by various browser versions in inconsistent ways, and might cause a jump to the top or the bottom of the current page, or add a useless extra page reference to the browser's session history. At least, if you must use such a dummy HREF, be sure to end your JavaScript command string with "return false" to discourage the browser from attempting to follow the dummy link.

Gracefully Degrading Menu Rollovers

Another popular effect is to have a graphical navigation menu do "rollover effects" when the user moves his/her mouse over the items, such as "lighting up" or "pushing down" the button that is in current focus, or showing more information about the currently-selected item to help the user decide whether to follow the link.

There are "graceful" and "non-graceful" ways to do this. The "non-graceful" ways can cause the navigation to fail completely for users who don't support (or have disabled) such things as Java, JavaScript, or Shockwave (depending on how the rollover is implemented). On the other hand, a "graceful" implementation leaves the site fully navigable even for "lowest common denominator" browsers, while adding extra enhancements for those who support them.

Sample code for a gracefully-degrading rollover effect is below. However, more than learning specific code, you should learn the general attitude behind this and other gracefully-degrading techniques in Web development. That is to use a sound, logical structure with simple, widely-supported HTML constructs, and then add the "bells-and-whistles" as optional add-ons which can be ignored by non-supporting browsers. The contrary attitude, which creates non-accessible sites, is to skip the "sound, logical, simple" stage and implement the desired effects directly in some advanced language (Java, Shockwave, etc.), ending up with code that doesn't even contain a "plain" HTML link that browsers can follow without running the "applet", "script", or "plug-in". Then, if such authors decide as an afterthought that they need to support "plainer" browsers, they end up sticking an ugly set of "alternative" text links below the "fancy" navigation, which wouldn't be necessary if they designed the site in a graceful manner in the first place.

Here's the "graceful" rollover code: (Note: In this example, the "normal" versions of the navigation buttons should be placed in item1_reg.gif, item2_reg.gif, etc., while the "mouseover" versions are item1_over.gif, etc. All images are to be placed in a subdirectory named gfx/ beneath the directory the page is in, and the images are all sized 250 x 50 pixels. Of course, you can change any of this as necessary for your own site.


<html>
<head>
<title>Sample Rollover Page</title>
<script language="JavaScript" type="text/javascript">
<!-- hide this script from non-javascript-enabled browsers
if (document.images) {
item1_reg = new Image(250, 50); item1_reg.src = 'gfx/item1_reg.gif';
item1_over = new Image(250, 50); item1_over.src = 'gfx/item1_over.gif';
item2_reg = new Image(250, 50); item2_reg.src = 'gfx/item2_reg.gif';
item2_over = new Image(250, 50); item2_over.src = 'gfx/item2_over.gif';
item3_reg = new Image(250, 50); item3_reg.src = 'gfx/item3_reg.gif';
item3_over = new Image(250, 50); item3_over.src = 'gfx/item3_over.gif';
item4_reg = new Image(250, 50); item4_reg.src = 'gfx/item4_reg.gif';
item4_over = new Image(250, 50); item4_over.src = 'gfx/item4_over.gif';
}
function rollover(id,name){
if (document.images) {document.images[id].src=eval(name+".src"); }
}
// stop hiding -->
</script>
<META http-equiv="Content-Script-Type" content="text/javascript">
</head>

<body>

<P ALIGN=CENTER>
<a href="item1/" onmouseout="rollover('item1','item1_reg');return false;" onmouseover="rollover('item1','item1_over');return false;"><img name="item1" src="gfx/item1_reg.gif" width="250" height="50" border="0" alt="[Item 1]"></a>
<a href="item2/" onmouseout="rollover('item2','item2_reg');return false;" onmouseover="rollover('item2','item2_over');return false;"><img name="item2" src="gfx/item2_reg.gif" width="250" height="50" border="0" alt="[Item 2]"></a>
<a href="item3/" onmouseout="rollover('item3','item3_reg');return false;" onmouseover="rollover('item3','item3_over');return false;"><img name="item3" src="gfx/item3_reg.gif" width="250" height="50" border="0" alt="[Item 3]"></a>
<a href="item4/" onmouseout="rollover('item4','item4_reg');return false;" onmouseover="rollover('item4','item4_over');return false;"><img name="item4" src="gfx/item4_reg.gif" width="250" height="50" border="0" alt="[Item 4]"></a>
</P>

</body>
</html>

Note the "if (document.images)", which ensures that only browsers using versions of JavaScript that can handle images (the earliest implementations couldn't) will try it, preventing errors. And note that the navigation images have ALT attributes containing the menu item text (change the "Item 1", "Item 2", etc. to more meaningful names given the sections of your site), so that even in text-only browsers the user can still navigate. And yes, I know, you can do rollover effects even more gracefully using cascading style sheets, but this is a pretty old page; until I do a massive rewrite of this entire site, it will have some fairly outdated stuff in it.

If you're letting some editor or utility program generate the "rollover effects" for you, make sure it's using a gracefully-degrading technique such as this, and make sure you put appropriate ALT attributes in the images (by hand, if necessary, if the program fails to give you a way to do it).

Client and Server-Side Forms

If you have a form that does useful things by means of JavaScript functions, it's still possible to allow it to gracefully degrade for users that don't have JavaScript, if you make sure it submits to a server-side form that performs the same functions, though not as efficiently as it can be done at the client side. For instance, a Web page where the user can type in their amount of savings per year and the expected interest or dividend rate yield and find out how much savings they'll have upon retirement can be done with JavaScript -- this produces a rapid computation without requiring anything to be submitted to a server, but doesn't work at all for users with JavaScript disabled. That can easily be remedied by having the submission action (in the absence of JavaScript) go to a server script that performs the same computations. The JavaScript "onsubmit" function can end in "return false" to prevent the server script from activating when it is not needed.

If your form is intended to submit to a server, but you still wish to use JavaScript functions also, such as to validate or correct the input before submission, then you should duplicate the same validation and correction steps in the server script so that they aren't skipped if JavaScript is not enabled or available. This is important for security purposes anyway, as a malicious hacker might create a version of your form that skips the JavaScript validation in order to attempt to input bogus data into your program, so it must be prepared to screen out such things. Some people on the newsgroups ask the wrong question, and say "How do I force my form not to appear, or not to submit, for users with JavaScript disabled, because my JavaScript validation is essential to their correct operation?" You can attempt to do this by making the submit button, or the entire form, be output by JavaScript instead of regular HTML, so it doesn't show up at all without client-side scripting. This can easily be defeated by malicious hackers who can view your source and reconstruct a form with a non-JavaScript submission button, but would pose an accessibility problem for more normal users. Better to design your server scripts so that they work well with or without the assistance of JavaScript.

Misconceptions

If you get into HTML discussions on newsgroups, you'll probably see somebody claim that "graceful degradation" really means making sites plain, boring, and "lowest common denominator." This is far from the truth. People who say it either don't truly understand graceful degradation, or are just trying to make cheap shots against the so-called "purists" rather than discuss Web authoring in a rational way. Actually, graceful degradation does not demand that you not use anything fancy or nice-looking, or that you "author for outdated browsers." It simply requires you to understand the structure of all the elements you use, and be aware of and properly use the built-in features that permit the insertion of alternative content that is accessible to users who can't or won't use the fancy stuff.

Graceful Degradation vs. Progressive Enhancement

There's been some discussion lately on Web development sites about the distinction in mindset between "graceful degradation" and "progressive enhancement", which are actually pretty similar concepts, but looked at from different directions. Wikipedia has an article on progressive enhancement, and there have been essays on the subject. The basic difference is that in "progressive enhancement" you begin with a simple, logical, compatible set of marked-up content, and then layer enhanced features for modern browsers on top of it, while "graceful degradation" begins with a full-featured, advanced site, full of bells and whistles, and makes sure it also has content that can be accessed if the fancy features don't work for a particular user. By this standard, the mindset I've advocated fits more in PE than GD, though I used the GD terminology because the other term hadn't been invented at the time. At any rate, if done skillfully, thoughtfully, and cluefully, both techniques should result in very similar sites.

Hall of Shame

Make your site better by looking at other sites that show, by example, what not to do!

NOTE: The inclusion of a site in my "Hall of Shame" links should not be construed as any sort of personal attack on the site's creator, who may be a really great person, or even an attack on the linked Web site as a whole, which may be a source of really great information and/or entertainment. Rather, it is simply to highlight specific features (intentional or accidental) of the linked sites which cause problems that could have been avoided by better design. If you find one of your sites is linked here, don't get offended; improve your site so that I'll have to take down the link!

  • The Leicestershire & Rutland Chess Association implemented their site so that the main page is buried deeper than the default index, which redirects to the real location of the home page. They used to do this with a meta-redirect and a fallback plain-HTML link, but after a redesign (why do redesigns almost always degrade accessibility compared to what went before?) they are using a default index consisting solely of a JavaScript redirect, so that non-Javascript users only get a blank page.
  • Hira used to offer a "Flash" and "Non-Flash" version on its front page, but the "Non-Flash" version still had Flash in it! It just skipped an extra "intro" page that has still more Flash. Now it doesn't do that idiocy, but it still has a Flash intro where the option to skip it is embedded in the Flash itself, meaning that non-Flash-supporting browsers will just get an empty page with no way to move on into the site. The intro plays annoying theme music continuously, with no way of stopping it.

Links

 

[<== Previous] | [Up] | [Next ==>]

 

This page was first created 19 Jul 1998, and was last modified 28 Aug 2019.
Copyright © 1997-2019 by Daniel R. Tobias. All rights reserved.

webmaster@webtips.dan.info