Progressive Enhancement
February 19th, 2010
Progressive Enhancement (PE) is an approach for building Web Applications that starts from the perspective that a user browser experience will support a minimum functionality, this is called base line, but has hooks to allow functional enhancements when a browser can support them. PE benefits users by supporting older browsers, but also supporting users with modern browsers and technologies by providing them an improved experience.
The progressive enhancement and its counterpart, Graceful Degradation, are approaches that can help rich Web Applications support more browsers and have a wider reach.
Disclaimer: We are writing this documentation as part of the new Web Client Guidance that is being done in patterns & practices. We are close to finishing this project, so I would like to get more feedback or validation from everyone that gets the chance to read this before we release. Have in mind that the content of this topic can change both in content and in form (it can change because of YOUR feedback).
Progressive Enhancement vs. Graceful Degradation
Graceful degradation is the practice of building an application for modern browsers while ensuring it remains functional in older browsers and other user agents (for example, accessibility tooling and mobile devices).
Progressive enhancement is usually preferable to graceful degradation: it starts with the simple basics and improves usability and aesthetics on top of that. When developing using Progressive enhancement you should define a development base, for example when using MVC the base could be a user that does not have JavaScript enabled. Therefore, the expectation is that you should have the basic functionality available without JavaScript; but with JavaScript, the experience is richer, including functionality, such as client-side form validation, predictive fetching, and preview.
It is strongly recommended to use progressive enhancement, when designing something from scratch. Graceful degradation can be tedious, difficult and requires more work to implement.
However, if you are maintaining an existing site, the easiest choice is to provide graceful degradation, unless you want to rewrite the whole site.
It is also possible to combine both approaches in the application. Even some features may end up being the same, independent of the approach used.
Note: For more information about both concepts, see Progressive Enhancements and Graceful Degradation: Making a Choice.
Core Principles
- Progressive Enhancement consists of the following core principles:
- The basic content should be accessible to all browsers
- The basic functionality should be accessible to all browsers
- Semantic markup contains all content
- Enhanced layout is provided by externally linked CSS
- Enhanced behavior is provided by unobtrusive, externally linked JavaScript
- End user browser preferences are respected
There are several scenarios to consider for using these patterns:
- Browsers that have JavaScript turned off
- Different browsers that:
- implement JavaScript and DOM features differently
- implement CSS differently
- The need for SEO (Search Engine Optimization)
Browsers that Have JavaScript Turned Off
Browsers may have JavaScript disabled due to company policies, screen readers, or other accessibility issues. This is usually the biggest challenge of all, as it requires the most development effort. If it is not done correctly, it could prevent the user from interacting with the site at all.
To address this scenario, you should start developing the site using HTML for the basic content. You should use semantic markup and CSS to enhance the layout. Then you should start adding functionality for browsers that do support JavaScript and other client technologies.
The following are some advantages and disadvantages of creating applications without JavaScript.
Advantages:
- Can support browsers without JavaScript
- It is SEO friendly (as search engine spiders do not use JavaScript)
- Easier to create an accessible site as a side effect without too much effort
- Possibility to open links in new tabs and bookmark it (for example if you use the middle mouse, it will open the link in href instead of executing the JavaScript defined for the click event).
Disadvantages:
- There is usually a need to create a server-side version of a view, and a separate client version of the same view or portions of it.
The developer has to be aware of the scripted and non-scripted features of the application, instead of just assuming that JavaScript will always be present.
Different Browsers that Implement JavaScript and DOM Features Differently
This challenge is typically known as cross-browser incompatibility. Compared to the previous scenario, when not implemented successfully, might prevent the user from interacting with the site in some cases, which causes frustration for the user, or even breaking JavaScript functionality completely, and cause a situation similar to the previous scenario.
This challenge has been a major pain point for web developers in past years, which led to using mostly server-side controls made by expert web developers that emit islands of JavaScript automatically, in order to prevent the application developer to have to learn all the browser differences, which in turn led to application developers from getting away from learning any JavaScript at all, even for simple tasks.
In recent years several JavaScript libraries have emerged that provide a cross browser experience for all of the most common tasks. By writing your code on top of these base libraries, in most cases you can avoid dealing with branching logic for the different browsers, which leads to a better appealing to the JavaScript language as a renewed development tool.
Different Browsers that Implement CSS Differently
CSS differences between browsers, though it is generally good to account for, it is usually not a big problem if bypassed. The reason is that having CSS that do not work in all browsers might cause some browsers to render the page with some inconsistencies in sizes, placement, overlapping of sections, but this will generally not prevent the user from interacting with the site entirely.
The following are some tips for dealing with these CSS inconsistencies:
- Use a CSS reset, which improve a lot of the cross-browser inconsistencies in size, placement, and overlapping issues.
- Develop the site with standards in mind (consider targeting XHTML 1.0 Transitional here), which almost always works in IE8, Firefox, Safari, Chrome, and usually Opera.
- If the standards targeted HTML/CSS has IE6/7 issues, fix those issues by including CSS “hacks†in separate stylesheets referenced through conditional comments.
It is up to the business to decide the ROI for creating a site that looks identical across all the browsers. Because not supporting all versions of CSS implementations will not prevent users from interacting with your site, you could typically decide to support the CSS features in the browsers with the largest market shares, while ignoring older browsers.
How to Achieve Progressive Enhancement
To implement PE you should begin with the basic version, and then add enhancements for those browsers that can handle them.
First, you should start developing your application in plain HTML. Plain HTML is understood by all browsers. Furthermore, search spiders will be able to access and index your site content.
This also means that all anchors and forms must have a working target URL for navigating or posting data without the need for JavaScript.
Then, add styles using CSS in an external file to improve the look and feel of the site. Almost all browsers support CSS, and those which do not support it, will simply ignore the styling.
Finally, add JavaScript support, using unobtrusive JavaScript. Unobtrusive scripts are silently ignored by browsers that do not support JavaScript, but it is applied by those that do it.
Unobtrusive JavaScript separates content from behavior. This means you should avoid having inline JavaScript as in the following example.
HTML
<form id=”profile” action=”http://mySite.com/SaveProfile”>
<input type=”text” name=”age” />
<input type=”submit” value=”Save” onclick=”SaveProfileWithAjax();” />
</form>
This is because the purpose of markup is to describe a document’s structure, not its programmatic behavior.
The unobtrusive solution is to register the necessary event handlers programmatically, rather than inline. This is commonly achieved by assigning a particular CSS selector to all elements which are affected by the script, to reduce the amount of script code. The JavaScript code should reside in a separate file. In the following code the id attribute is used for identifying a form:
HTML
<form id=”profile” action=”http://mySite.com/SaveProfile”>
<input type=”text” name=”age” />
<input type=”submit” value=”Save” />
</form>
It is recommended that you use libraries that provide an abstraction of the DOM. The jQuery and ASP.NET Ajax libraries do a good job at this.
The following jQuery script binds the submit event of the form with id=”profile”, to the SaveProfileWithAjax function:
Note: jQuery simplifies this, by providing a CSS-like selector, instead of just getting the elements by ID.
JavaScript using jQuery
$(document).ready(function(){ //Wait for the page to load.
$(’form#profile’).bind(’submit’, SaveProfileWithAjax);
});function SaveProfileWithAjax(event){
event.preventDefault(); // this will prevent the browser for submitting the form in the default way, as we will handle the post programmatically using AJAX
// Post the data using an AJAX call
}
Note: The event.preventDefault JavaScript method cancels the event if it is cancelable, meaning any default action normally taken by the implementation as a result of the event will not occur.
The following code shows the implementation in ASP.NET Ajax Library.
JavaScript using ASP.NET Ajax Library
Sys.Application.add_init(function() {
$addHandler($get(’#profile’), ’submit’, SaveProfileWithAjax);
});function SaveProfileWithAjax(event){
event.preventDefault();
// Post the data using an AJAX call
}
Note: To attach events, modern browsers use the addEventListener function specified in the DOM Level 2 (Events) specification, while Internet Explorer will use its proprietary attachEvent function. For this reason, if you want to achieve cross-browser compatibility in a simple manner, you should always attach events using a library like jQuery or ASP.NET Ajax Library, which automatically deals with these compatibility issues.
Tips for Achieving Progressive Enhancement in ASP.NET MVC
Consider the following tips when implementing the progressive enhancement pattern in ASP.NET MVC.
First, build an HTML feature that works without JavaScript. For example, the song rating functionally of the Reference Implementation, which was created using radio buttons.
The following rules are applied to every web application (not just ASP.NET MVC ones) to achieve PE.
- Use semantic markup to render the basic content.
- Use CSS to enhance the layout.
- Anchors should always have the href attribute set to return a working view from a controller.
- Forms should always have the action attribute set to post the data to a working action in a controller, based on the input elements in the form. Consider rendering hidden inputs for preset values that the users don’t need to update or see.
Once the basic functionality works without JavaScript, consider the following:
- Enhance the experience using Unobtrusive JavaScript. This typically includes:
- Adding client-side validation to acquire immediate feedback without requiring a full post.
- Converting full page POST/GET requests into AJAX calls that update portions of the page.
- Adding animations / eye candy features.
- When converting a full page request into an AJAX call, hijack and prevent the default action of the anchor link or form submit, and replace it with the AJAX call. You typically do this by calling the preventDefault method of the arguments object received when handling the click/submit event using JavaScript.
- Avoid having different URLs for accomplishing the same business result for these cases. You can add branching code in your controller that checks the Request’s headers to see if it is an AJAX call as opposed to a typical GET or POST call, and return a different result in this case.
- Typical approaches include returning partial HTML markup to be inserted without processing into the DOM, or data represented in JSON that requires some processing in the browser to display it.
- ASP.NET MVC provides a standard way of checking if the request was initiated using XmlHttpRequest by calling the Request.IsAjaxRequest() extension method
Note: If you use ASP.NET WebForms instead of ASP.NET MVC, you might need to create different endpoints, such as Web Services, ASP.NET Page Methods, or even expose MVC controllers for these actions, as there is no easy way of reusing the same endpoint, because a URL maps to a physical ASPX file.
- In the cases where you return JSON, you might need to use JavaScript to directly manipulate the DOM, or when possible, have a template view that renders data that was retrieved in JSON format. Having templates can help you better separate UI logic from the model in the JavaScript code. The ASP.NET Ajax Library has a very good templating engine that allows you to bind to a ViewModel in a somewhat similar way as WPF & Silverlight. For more information, see Isolating the Domain Model from the Presentation Layer (this is in the Web Client Guidance documentation).
- In some cases, you may have DOM elements that only make sense in a non-JavaScript version of the page. This is common, and you might want to remove these elements by using JavaScript if it is available in the browser.
For example, you may have a link that redirects to a different page, but when you enhance it with JavaScript, you might hide those links entirely, and replace it with a much richer experience that does not require a redirect for example.
Note: You can also use the noscript HTML element to render content when JavaScript is not enabled or not supported by your browser. - Cascading drop-downs is another canonical example: If you have a State drop down, that once selected will set available cities in another drop-down, the non-JavaScript version will have a visible submit button, and so after setting the State, the user can POST back to the server and get the same page with the available cities already populated. When JavaScript is enabled, after the page is loaded, you might want to hide this button, and on selection change of the State dropdown, request the available cities with an AJAX call that returns JSON, and update the dependant Cities dropdown. There is no need for the user to explicitly click the button to get the cities.
Finally, move on to the next feature. Remember, to always build a non-JavaScript version of a feature, and enhance it afterwards. There might be secondary features in the application where you can decide to implement in browsers that only have JavaScript enabled, but you should make this decision consciously, identifying the risks for not supporting that scenario.
Sources
- Progressive Enhancement and Graceful Degradation: Making a Choice
- Progressive enhancement
- Unobtrusive JavaScript
More Web Client Guidance
You can find this and many other topics and key decisions for creating web client applications (both in ASP.NET Web Forms and ASP.NET MVC) in our latest Web Client Guidance drops. We are close to finishing this guidance, so your prompt feedback is invaluable to us. Make sure you check it out and comment in this topic or in the codeplex forums (there is a special tag to mark conversations for this new guidance)
The Single Page Interface Pattern
February 17th, 2010
Problem
Typically, the user interface in Web Applications is composed of multiple pages. Now with the increasing popularity of AJAX, it is common that people want to develop Web applications that are similar and provide the same user experience as desktop applications. One common problem in Web applications is the constant page reloads and flickering when navigating the application.
Disclaimer: We are writing this documentation as part of the new Web Client Guidance that is being done in patterns & practices. We are close to finishing this project, so I would like to get more feedback or validation from everyone that gets the chance to read this before we release. Have in mind that the content of this topic can change both in content and in form (it can change because of YOUR feedback).
Forces
Any of the following conditions suggest using the solution described in this pattern:
- You want to minimize the page reloads and flickering when navigating through the application.
- You want to change only the content of the page and maintain the general layout; that is the header, footer, and menus, when updating the page.
- You want the user to keep the context of most of the page, while only manipulating the data on part of the page.
- You want to have long running processes and/or avoid losing/refreshing dynamic content state while navigating (for example, uploading files or a chat window).
- You want to improve the user experience of Web applications, by simulating the look and feel, and usability of desktop applications.
Solution
Have all of your page features, or at least most of them, in a single page. This is known as the Single-Page Interface (SPI) model. In the SPI model, all browser interactions with a Web application occur inside the boundaries of one page.
The SPI pattern improves the UI navigability of Web applications because it decreases the number of page reloads and eliminates flickering.
The SPI model requires a number of highly interactive features, which include in-place editing, context-sensitive user interface, immediate user feedback prompts, and asynchronous operations.
The Single-page Interface pattern elements
SPI is an AJAX pattern that suggests you have only a main page in your Web Application. This page interface is rearranged as a result of user interaction with the application.
Having a single-page interface, may result in your application using less-distinct URLs. Therefore, this pattern may not provide good support for search engines, unless explicit mechanisms for also allowing the navigation of the site by using full redirects are implemented.
Liabilities
The Single-page Interface pattern has the following liabilities:
- As all interactions occur within a page, there are less distinct URLs. Therefore, this pattern does not inherently provide good support for search engines
- You need to implement a mechanism to identify the different states of the application; this is for providing history browsing support and bookmarking. It might be used also for supporting permanent link. Unique URLs and deep linking can be supported in an SPI app but with additional development cost. Web applications built using more traditional full page refreshes support unique URLs and deep linking more easily.
- You have to be careful with memory leaks, because as the page is not refreshed as often, the memory is not cleaned automatically by the browser. Therefore you have to manually dispose objects, handlers, and so on, when navigating through the page.
- The SPI pattern requires a lot of JavaScript. If JavaScript is turned off, the user will not be able to use the application. This then requires down-level support in addition to the SPI pattern. It makes more sense to implement the SPI pattern if you have more control of your browsers, for example, if you have an intranet application and you know the corporate image does not restrict JavaScript, then SPI might work here. For the Internet case, it is more mixed because some users will enable JavaScript and some will not.
- Consider using the Progressive Enhancement or Graceful Degradation pattern, for addressing accessibility, browsers where JavaScript is disabled, and search engine optimization. Otherwise older browsers or readers will not be able to use your application. If you choose to support accessing the website without the use of JavaScript, the complexity of the application increases exponentially, as you would typically need to create server and client side version of most of the views. This approach can also help to add better support for search engines.
Identifying the State of an Application with Distinct URLs
When using AJAX and the SPI pattern, an application may perform different operations, and therefore pass through different states while the URL in the browser stays constant. This creates the need of a mechanism to identify different states of the application, for example, for moving back to a previous state.
Browsers implement the Back and Forward buttons functionality by caching the list of visited URLs.
In AJAX, the server communication is done through XMLHttpRequests, and these requests do not change the page URL. Therefore, the list of visited URLs is not modified.
The Unique URLs pattern helps addressing this problem, by assigning a unique and expressive URL to each significant application state.
Scripting does not provide a mechanism to modify the list of visited URLs, but it provides mechanisms to modify the URLs.
You can manipulate the URL with JavaScript using the window.location.href property, but this will trigger a page reload; fortunately you can use the window.location.hash property. The hash property is used for fragment identifiers, which are optional components of URLs that came after the hash character (#). The string that comes after the hash character is not sent to the server; therefore, the browser is responsible for restoring the state through client scripts, and retrieving the appropriate views. Because they are like normal links, but within a single page, no page reload occurs, and the browser behaves as if you have clicked a standard link, adding the URLs to the list of visited URLs. This also enables history navigation, bookmarking and sharing URLs with other people.
Note: Setting the hash property does not work reliably on all browsers, and you do not get change notifications on all browsers either. For this reason, it is recommended using some library that handles these differences in a cross-browser way, such as the Microsoft Ajax Library History control.
Therefore, when there is an important state change in your application, modify the URL hash property. In this way the changes will be tracked by the browser.
JavaScript
window.location.hash = stateData;
The resulting URL will look like the following.
URL
http://www.mycompany.com/mypage.aspx#someState
Once you have identified each relevant state of the application, you need to implement code to parse the URL. You can choose the format based on your specific needs to represent a state, you can even add parameters in the URL, as seen in the following example.
URL
http://www.mycompany.com/mypage.aspx#viewProduct=5529
Finally, after parsing the URL, you should restore the application to the corresponding state based on the hash data, keep in mind that the hash data is not sent to the server as part of the URL. In the previous example, when loading that URL, the application should go to the product details form, showing the details of the product with ID 5529.
More Information
For more information about the Single-Page Interface pattern, see the following:
- Single-Page Interface and AJAX patterns on MSDN Magazine
For more information about software design patterns applied in the Web Client Guidance, see Patterns in the Web Client Guidance.
You can find this and many other topics and key decisions for creating web client applications (both in ASP.NET Web Forms and ASP.NET MVC) in our latest Web Client Guidance drops. We are close to finishing this guidance, so your prompt feedback is invaluable to us. Make sure you check it out and comment in this topic or in the codeplex forums (there is a special tag to mark conversations for this new guidance).
ASP.NET Ajax Library or jQuery?
February 8th, 2010
I get this question very often. Should I you the one or the other?
Well, my short answer in most circumstances is “you should use both“.
My long answer is “it depends on what you are trying to achieve”, and this blog post will try to cover what are the strengths of each of the libraries, and also why it’s OK to use both with the overhead this “might” have.
Disclaimer: We are writing this documentation as part of the new Web Client Guidance that is being done in patterns & practices. We are close to finishing this project, so I would like to get more feedback or validation from everyone that gets the chance to read this before we release. Have in mind that the content of this topic can change both in content and in form (it can change because of YOUR feedback).
Also, this topic was created using ASP.NET Ajax Library 0911 beta and jQuery 1.3.2.
Guidelines for using ASP.NET Ajax Library and jQuery
There are different JavaScript libraries that can assist you in authoring JavaScript code that runs on the browser, and using at least one of them is an absolute must in today’s environment. Though ASP.NET WebForms is better suited -but not limited to- for using the ASP.NET Ajax Library, ASP.NET MVC has no preference over either ASP.NET Ajax Library, jQuery or other 3rd party libraries. Furthermore, ASP.NET Ajax Library and jQuery can work especially well together and complement each other, whether you render markup using WebForms or MVC.
ASP.NET Ajax Library and jQuery can be used together in the same Web application, and they both have support from Microsoft. These libraries do not conflict with each other, but they complement each other greatly. The overlap between functionality is not big, and since jQuery’s official support by Microsoft, this overlap is getting reduced in every release.
ASP.NET Ajax Library has made important changes to its core to leverage jQuery functionality when it detects that jQuery is also loaded. For example, ASP.NET Ajax Library provides some basic jQuery-like selector support for selecting DOM elements for its Sys.get(selector) method, which is used internally by many other components. Nevertheless, when jQuery is available, the selector passed into this method can be very complex, because it will delegate the DOM selection to jQuery under the hoods. Furthermore, all ASP.NET Ajax Library controls and plugins, are also exposed automatically as jQuery plugins.
We found that in most cases, although there is an additional cost for downloading the 2 libraries instead of just one, the productivity and features covered by both libraries working together far outweighs that cost. Also, keep in mind, that if your application is hosted in the internet, as opposed to an Intranet, it is strongly recommended that you use the Microsoft CDN, so the download time gets reduced, and sometimes skipped, as the files may be cached by the browser.
The following sections define some pros that we found when using a particular library over the other. This list should not be taken as completely objective or closed, as depending on what plugins you decide to use, there might be advantages or disadvantages for each. These guidelines are based on the experience developed by using both ASP.NET Ajax Library and jQuery when building web applications in the last few months, as Microsoft has recently added support for jQuery from within Visual Studio, and the ASP.NET Ajax Library has taken huge steps towards supporting both libraries side by side.
Why should you use jQuery
One of the more important reasons for using jQuery is for DOM (Document Object Model) manipulation.
- The jQuery library is extremely easy to use for finding elements using selectors, for moving elements to different locations inside the DOM, changing element classes, basic animations, and so on.
- jQuery has a simple API for handling DOM events. However, this functionality is comparable to what can be accomplished with ASP.NET Ajax Library. Due to this, in the Reference Implementations both approaches are used interchangeably; depending on what was the handling logic being used for (that is, DOM manipulation, controlling logic, and so on).
Another strong point of jQuery is the Developer community behind it.
- Because jQuery supports only client-side functionality, it is server-side technology agnostic, and has a powerful extension mechanism.
- For the previous reasons, it has been more widely used to develop plugins for a lot of different situations. These plugins are available through the official jQuery site, although each of them has its own license. Nevertheless, a big percentage of these plugins use very permissive open source licenses, an most of them use the same license as the jQuery core, to ease adoption for users who are already using jQuery.
Why should you use the ASP.NET Ajax Library
We found the ASP.NET Ajax Library to be especially useful for writing JavaScript logic whose objective was not just manipulating or animating the DOM. Also, the script loading capabilities was of great help in both the perceived performance of the application and in the development and organization of the JavaScript code.
Some other strong points of the ASP.NET Ajax Library are the following:
- API and syntax similar to the .NET framework. The library imitates the .NET framework API, type system and namespaces hierarchies, therefore the developers familiar with the .NET framework can learn this framework with ease.
- The Ajax Script Loader that comes with the library is useful for loading scripts in parallel and for managing dependencies. Using the Script Loader gives you the following advantages.
- Minimize an Ajax application’s render time
- Handle loading script dependencies
- Leverage script combining techniques
- Perform lazy loading of scripts behind the scene
Note: For more information about the ASP.NET Ajax Library Script Loader, there is a specialized Script Loading document in the Web Client Guidance, make sure to check it out.
- It is especially useful for writing logic that does not only manipulate the DOM. It provides infrastructure for creating JavaScript controls and behaviors (extending the Sys.Component type), and also provides memory management, easy control creation/instantiation.
- You can use Client Templates to bind the UI to an observable view model. This allows separating the concerns of UI specific code (or DOM manipulation) from the presentation logic. This also simplifies unit testing the JavaScript code by avoiding the need to test the DOM state and user interaction directly.
- Browser history: When the state of a web page changes by using Ajax calls to the server, the URL in the browser does not change automatically. The ASP.NET Ajax Library simplifies working with the browser history, with a cross-browser approach.
- The Ajax Control Toolkit is a set of reusable controls that can be used from both ASP.NET Ajax Library and jQuery using JavaScript code, and is also very friendly for using it from server-side generated JavaScript, especially when using ASP.NET WebForms server controls.
- It provides auto-generated proxy classes that simplify calling Web service methods from client scripts.
- When using ASP.NET WebForms, the ASP.NET Ajax Library is the easiest to use in several scenarios, as many of the controls and functionality can be used from their server-side controls counterparts.
- Working with ADO.NET Data Services is very easy with the ASP.NET Ajax Library. This, in combination with Client Templates can help creating client side views that consume data from the server very easy.
More Web Client Guidance
You can find this and many other topics and key decisions for creating web client applications (both in ASP.NET WebForms and ASP.NET MVC) in our latest Web Client Guidance drops. We are close to finishing this guidance, so your prompt feedback is invaluable to us. Make sure you check it out and comment in this topic or in the codeplex forums (there is a special tag to mark conversations for this new guidance)