Progressive enhancement
It’s never a certainty that your user will experience your site exactly as you intended. There are just too many possible failure points eg. -
- Patchy Internet connection
- Your Javascript fails to run fully in the browser because some 3rd party code elsewhere in the page blows up (eg analytics, advertising)
- A stylesheet fails to download
- An error in the server side application causes some or all of the page not to render
- Small screen size crops half the page width
If you make core content completely reliant on complex client-side processing, you’re making yourself a hostage to fortune. It also makes it harder to adapt it for viewing on different devices.
Progressive enhancement is about maximising the chances that your user will be able to experience the core content and user journeys they want from your site.
This means you should lay a foundation of code that will show core content and allow links and forms to function even if CSS and Javascript aren’t there.
You can then layer on Ajax, CSS3 etc to enhance the experience for capable browsers.
Some examples:
| Doing it wrong |
Doing it right |
| A form submit button is made using a link wired to some Javascript which will validate then submit the form. |
The form submit button is either an < input type=”submit” /> or <button type=”submit”> </button> |
| Only supporting a form submit using Ajax, ie any request to the form action URL, whether marked as Ajax or not, will return a markup snippet |
Without Javascript, the form action should return a full page as a response |
| Styling a content panel with display:none on page load, as it can be shown using a javascript-powered button |
Use Javascript to add a ‘.js-enabled’ class to your <html> or <body> tag then prefix your style rule with that eg..js-enabled .my-div { display: none }.The style will then only be applied if Javascript is enabled |
Performance
Meaning both the speed of the initial download, and the responsiveness of the UI. Performance is a feature, with a direction positive correlation to user satisfaction and good SEO.
A decent build process is key to fast page load, to transform readable dev code into compressed, concatenated production code without an ounce of fat on it.
On initial page load, I believe content should be rendered to HTML on the server – it’s faster, more robust and more maintainable than passing data and templates to the front end and resolving there.
UI responsiveness comes from a lightweight DOM, and any interaction with it from the code should be minimised and as efficient as possible. Using a context for DOM selectors speeds things up eg. search from the module / widget container -
$('#myModule').find('.nav-update');
rather than starting from the document root -
$('.nav-update');
Maintainability
Developers leave projects and new ones join who have to pick up the code base. Often it will be ditched and coded from scratch because the last developer never considered the next person. Tightly coupling the layers of HTML, CSS and Javascript creates a code base that can’t be easily repaired, re-used or evolved.
Stay DRY – use HTML templates with re-usable snippets, a CSS processor and modular Javascript with classes and mix-ins to prevent duplication.
Robustness
Code defensively – check an item is available before you try and use it.
Use loosely coupled modules. Each should be able to exist on a page either on its own, or with other modules, without impairing them.
Write Javascript unit tests for low level verification. Use a tool like Selenium 2 / Webdriver to write automated functional tests that you can re-run. The extra effort buys you confidence that your site works and will survive future changes without regressions.
Efficient development
Do many clients and product owners understand that even though <5% of their users are on IE6 and even IE7, it could burn 10 – 15% of their budget to support these outdated browsers, with the additional cost of dragging down functionality for modern browsers?
If not, it’s our responsibility as front end developers to make this information available so a balanced decision can be made.
The increasing view, promoted by developers like Andy Clarke and Paul Irish, is that a page shouldn’t have to look exactly the same in legacy browsers. The trade-offs just aren’t worth it.
Supporting IE7 should mean core content and user journeys are achievable, not that semi-transparent drop shadows have to be faked using filters that slow the page down further.
The components
1. HTML5
A base of HTML5 markup including semantic elements – <nav>, <footer> etc.
Add a wrapper <div> inside each and style those, then it all works in IE6, 7 and 8 without having to use Javascript createElement to make <nav> etc stylable.
Add classes for meaning only, never styling (see CSS section for how to achieve this without having to repeat presentational styles between classes in your stylesheet).
2. CSS3
Rounded corners are for browsers that understand border-radius. Slowing the page down by using heavy, unreliable VML (CSS3Pie) or Javascript to fake this effect, hits download and rendering performance, robustness and maintainability.
Very limited use of proprietary IE filters to apply gradients, can bring the design closer to the comp, but additional use of a filter slows the page down more.
Use a CSS processor like LESS to centralise shared styles and apply those to your semantic styles without having to repeat them through your stylesheets.
3. Javascript
As Douglas Crockford pointed out, the browser is the most hostile programming environment there is. Assuming your Javascript makes it over the wire, and it’s enabled by the user, a 3rd party script could blow up in the page before a single line of yours has executed. You can’t and shouldn’t rely on Javascript only to deliver core content or key user journeys eg. form submits. In other words, core functionality should be able to fall back to links and form posts.
Use a library, and be able to choose the right one for the project’s needs.
jQuery is a genius piece of engineering with fantastic documentation but it’s designed to cover just four areas:
- DOM interaction
- Ajax
- Events
- Effects.
If you’re working on anything more than a few pages with simple functionality, you may need to cover additional areas including:
- Namespacing
- Modular code
- Common functionality for UI widgets – progressive enhancement, accessibility, listen / broadcast to other modules (observer pattern)
Having used YUI3 intensively on a large project, I’m sold on the advantages of using a library that covers this stuff, rather than coding the same (but different) solutions for each project. The documentation part is then largely covered and new developers can get up to speed quicker.
[EDIT Dec 2012] – looking back at this last comment, I’d have to disagree with myself… Having now used code organisation libraries such as Backbone and RequireJS, those extra needs can be fulfilled without a single monolithic library like YUI. jQuery’s popularity remains unassailable and there are good reasons for that; and the front end community (including myself) tends to favour mix and match solutions on top of jQuery.