Progressive enhancement is a technique used by web developers to ensure that their pages are accessible to as wide an audience as possible while at the same time trying to take advantage of the latest browser enhancements to provide the best user experience for their users. The basic idea behind progressive enhancement is to start off by creating a basic version of your page that contains your content and semantic markup that is supported by the lowest common denominator browser you intend to target. Once you are done, you can then alter the display and behavior of elements on the page with the use of technologies such as CSS, JavaScript, and Flash.
By designing your pages in this manner, the user and any assistive technologies they use, or search engine spiders, should be able to access your page content, even in the absence of CSS, JavaScript and Flash.
This document will give examples of how to use the various components within Spry in a progressive enhancement scenario and introduce some techniques and utilities that will hopefully make it easy:
Here is a very basic example that illustrates progressive enhancement with JavaScript. Given the following basic markup:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Basic Markup</title> </head> <body> <div id="event"> <h2 class="name">Aquo-Thon</h2> <div class="info"> <div class="location">Whistler, British Columbia</div> <div class="date">May 26th</div> <p class="description">Join us in Whistler as Extreme Mountain bikers take on the hills and curves of British Columbia.</p> <a href="#">directions...</a> </div> </div> </body> </html>
We can progressively enhance it so that each time the user's cursor is over the content, it turns a different color:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Basic Markup</title>
</head>
<body>
<div id="event" onmouseover="this.style.backgroundColor = 'yellow';" onmouseout="this.style.backgroundColor = 'white'">
<h2 class="name">Aquo-Thon</h2>
<div class="info">
<div class="location">Whistler, British Columbia</div>
<div class="date">May 26th</div>
<p class="description">Join us in Whistler as Extreme Mountain bikers take on the hills and curves of British Columbia.</p>
<a href="#">directions...</a>
</div>
</div>
</body>
</html>
In the example above, onmouseover and onmouseout attributes were added to the <div> with the id of "event". The value of each of those attributes is some JavaScript that the browser will execute anytime the user's cursor enters or exits the "event" <div>. While this is a very trivial example, it illustrates the addition of a behavior to the basic page. With JavaScript on, users will see this new behavior as they move the cursor around on the page, but, with JavaScript off, all of the content on the page is still accessible.
Because Spry Effects and Widgets both work on elements that *must* be present within the page, they are well suited for use with progressive enhancement. For example, given this basic semantic markup:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Basic Markup</title> </head> <body> <div id="event"> <h2 class="name">Aquo-Thon</h2> <div class="info"> <div class="location">Whistler, British Columbia</div> <div class="date">May 26th</div> <p class="description">Join us in Whistler as Extreme Mountain bikers take on the hills and curves of British Columbia.</p> <a href="#">directions...</a> </div> </div> </body> </html>
(Click here to see a live version of the example above.)
We can progressively enhance this markup with CSS and some JavaScript behaviors that turn it into a collapsible panel:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Progressively Enhanced Markup</title> <script type="text/javascript" src="../../../widgets/collapsiblepanel/SpryCollapsiblePanel.js"></script> <link href="css/sample.css" rel="stylesheet" type="text/css" /> </head> <body> <div id="event"> <h2 class="name">Aquo-Thon</h2> <div class="info"> <div class="location">Whistler, British Columbia</div> <div class="date">May 26th</div> <p class="description">Join us in Whistler as Extreme Mountain bikers take on the hills and curves of British Columbia.</p> <a href="#">directions...</a> </div> </div> <script type="text/javascript"> <!-- var cp = new Spry.Widget.CollapsiblePanel("event", { contentIsOpen: false }); --> </script> </body> </html>
(Click here to see a live version of the example above.)
In the example above, SpryCollapsiblePanel.js was included to enable support for a collapsible panel. We also includes a stylesheet that has some rules that make the "event" div look like a collapsible panel. At the very bottom of the document is a script block which attaches the collapsible panel behaviors to the "event" element and some of its descendants.
If you load the example above into your browser, you'll notice that the page displays a collapsible panel tab. If you click on this tab, it animates to reveal additional content. If you turn off CSS and JavaScript support in your browser and re-load this same example, you will notice that the content is entirely accessible, just as it is in the basic example.
Here's an example of progressively enhancing the same basic source with an effect that highlights the content as you mouse over its header:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Progressively Enhanced Markup</title> <script type="text/javascript" src="../../../includes/SpryEffects.js"></script> </head> <body> <div class="event"> <h2 class="name" onmouseover="Spry.Effect.DoHighlight('AquoThonContent', {from: '#FFF', to:'#FFCC33', toggle: true });" onmouseout="Spry.Effect.DoHighlight('AquoThonContent', {from: '#FFF', to:'#FFCC33', toggle: true });">Aquo-Thon</h2> <div id="AquoThonContent" class="info"> <div class="location">Whistler, British Columbia</div> <div class="date">May 26th</div> <p class="description">Join us in Whistler as Extreme Mountain bikers take on the hills and curves of British Columbia.</p> <a href="#">directions...</a> </div> </div> </body> </html>
(Click here to see the sample above in a browser.)
As with the previous example, if you turn off CSS and JavaScript in your browser, the content is still accessible.
Before integrating support for Spry data sets and regions into your existing pages, take a moment to think about how and where within your site this support will be surfaced, and about the potential impact this may have on the accessibility and search engine indexing of your site. For some folks, after playing with some of the Spry demos and samples, their first inclination is to externalize all of the content from their existing pages so they can use data sets and regions to swap out the page contents without full page refreshes. For example, they start using pages that look like this throughout their site:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Page With No Content Sample</title> <script src="../../../includes/xpath.js" type="text/javascript"></script> <script src="../../../includes/SpryData.js" type="text/javascript"></script> <script type="text/javascript"> var dsEvents = new Spry.Data.XMLDataSet("events.xml", "/events/event"); </script> </head> <body> <div id="content" spry:region="dsEvents"> <div spry:repeat="dsEvents" class="event"> <h2 class="name">{name}</h2> <div class="info"> <div class="location">{location}</div> <div class="date">{date}</div> <p class="description">{description}</p> <a href="{location}">directions...</a> </div> </div> </div> </body> </html>
(Click here to see the sample above in a browser.)
Although it looks fine and renders with content in a browser when JavaScript is turned on, it renders without content when JavaScript is turned off:
(Click here to see the example above in a browser.)
This means the content is not accessible to users and screen readers when running in an environment where JavaScript must be turned off. This is also what most search engine web crawlers will see, which means your content will not be found and indexed.
The only way to solve this problem is to follow the progressive enhancement methodology, and start with a basic page that actually contains static content.
Over the last few releases, the Spry team has been steadily introducing new features within the framework that will allow the developer to progressively enhance their pages to load content dynamically. These features include the use of the spry:content attribute within regions, the HTML Data Set, Spry.Utils.updateContent() utility method, and the HTML Panel Widget.
Below are some samples of how to use various features within Spry to progressively enhance your static pages so they can dynamically load new content.
Each feature comes with a set of requirements, so which feature you decide to use depends on what it is you are trying to accomplish. For example, if you are trying to make a page dynamically load and display *existing* HTML content without resorting to modifying or creating any server-side scripts to serve up fragments of your existing pages, you may want to use an HTML Data Set or the HTML Panel since they both have the ability to extract HTML fragments out of existing pages. Or, if you want to take a server side approach and serve up HTML fragments embedded within XML/JSON or some other format, along with instructions on where to insert them on the page, perhaps using a data set, suited to the particular format being served (XML, JSON, etc), with or without regions is a better approach.
The samples below all start with a page that contains static content, and links that take you to other pages with static content. They are then progressively enhanced with JavaScript to intercept clicks on links to prevent the browser from following the link and instead trigger some code we added to dynamically load content and replace portions of the page without a full page refresh. If this concept sounds familiar to some folks, its because it is the same approach described by the Hijax methodology.
Copyright © 2007. Adobe Systems Incorporated. All rights reserved.