Blog

Nous parlons de design, de techniques, de tendances, du métier et de nos projets.

Progressive Enhancement in Action, Part 1

publié par Régis
Déc 17 2008

One of the things I will cover in future installments is a design and development philosophy called progressive enhancement. There’s no place here for all the historic background that comes into the rise of progressive enhancement as a de facto approach in web design today, but the big picture has been covered in 3 articles written by web standards guru Aaron Gustafson and I highly recommend you read them on—surprise—A List Apart: number one, number two and number three.

Without further ado, let’s introduce the first in a series of four articles showing examples of progressive enhancement in action.

Add as Friend

The examples I’ll be working on are the dialog boxes that pops up on Facebook when you trigger specific actions, such as adding someone as a friend, sharing something or suggesting friends. For the sake of this article, I’ll focus on a specific detail of these dialogs: the thick border around these boxes. You’ll notice they have used a semi-transparent black border with rounded corners.

That design supports the clean and minimalist style of the site and guides the user’s eyes into the content of the dialog, where attention is required. Anyone who has ever worked with transparency and rounded corners knows how annoying it is to deal with them, especially when one spends more time hacking around browser bugs than anything else more useful.

Consistency, in the context of an application that is used by millions of people, comes at a premium. Though I personally disagree that websites should look the same in all browsers, I understand that Facebook developers looked after it in order to allow for the exact same experience on all the major platforms. However, this choice inevitably led to break all the rules of meaningful markup, cluttering the code with elements used for their presentational aspect rather than for their meaning. This is not a recommended approach for any website whatsoever and Facebook is no exception.

Progressive enhancement, on the other hand, is solidly rooted in concepts such as semantic markup and accessibility in order to provide the best experience to the full spectrum of user-agents browsing the Web. Incremental enhancements are brought on top of the content without sacrificing its meaning and therefore its universality.

Let’s take a look at the markup used for dialogs on Facebook:

<table class="pop_dialog_table" id="pop_dialog_table" 
       style="width: 532px;">
<tbody>
  <tr>
	<td class="pop_topleft"  />
	<td class="pop_border"  />
	<td class="pop_topright"  />
  </tr>
  <tr>
	<td class="pop_border"  />
	<td id="pop_content" class="pop_content">
	  <!-- here comes the content -->
	  ...
	</td>
	<td class="pop_border"  />
  </tr>
  <tr>
	<td class="pop_bottomleft"  />
	<td class="pop_border"  />
	<td class="pop_bottomright"  />
  </tr>
</tbody>
</table>

As you can see, it’s a classical example of table-based markup, though you’ll notice it is free of the infamous spacer GIF that used to come along that ill-fated technique; a midway solution of sorts that uses CSS instead, some may deem it acceptable. Well, for the purpose of this article, we don’t. Compare it to this more appropriate semantic equivalent:

<div class="dialog">
  <!-- here comes the content -->
  ...
</div>

Removed from the clutter of presentational markup, information surfaces and nothing gets in the way. And nothing should anyway, especially when the purpose is to decorate the content with visual ornaments.

Semi-transparent borders

Now that we’re done with the markup, let’s focus on styling. Normally, semi-transparent backgrounds are achieved by means of PNG images or empty DIVs using the opacity CSS property, both these solutions require extra markup that we don’t want. Instead, we’ll use a feature that has been introduced in the CSS3 Colour Module, RGBA color values. RGBA uses the RGB color gamut and includes a 4th value for the alpha channel, you can use it everywhere color is allowed. You may or may not know it, but some of CSS3 new features are already implemented in progressive browsers, i.e. those based on Webkit (Safari and Chrome) or Gecko (Firefox 3+), we can use them right now. In our case:

.dialog { border: 10px solid rgba(0, 0, 0, .5); }

Notice the .5 in the declaration above, it simply means we want to apply a 50% transparency. We’ll see later how we can deal with browsers that don’t support RGBA.

Rounded corners

Rounded corners have always been a hassle to implement. Depending on how much flexibility is needed, several techniques have been there for a long time. In this example, maximum flexibility is needed as the data contained within dialogs can differ drastically from one case to the other and the box needs to have the appropriate size.

In traditional development, additional markup would be needed to accommodate the four corners, using some CSS and background images. Once again that’s something we don’t want. Fortunately, rounded corners have been introduced in CSS3 as well and already work quite well in aforementioned browsers. As the CSS module is not a Candidate Recommendation yet, you’ll have to specify this property using a vendor-specific extension (-webkit- and -moz- respectively). Here it is:

.dialog { 
  border: 10px solid rgba(0, 0, 0, .5);
  -webkit-border-radius: 8px;
  -moz-border-radius: 8px;
  border-radius: 8px; }

There we have it. The exact same behavior as on Facebook, with much more flexibility (you can change any border properties with just a few keystrokes), accessibility (nothing presentational gets in the way) and swiftness (pages saved from extra markup and a few http requests run just faster).

How to deal with other browsers

Progressive enhancement occurs naturally here, for according to the CSS specification, browsers must simply ignore properties and values they don’t understand. Therefore, those browsers (mainly IE and Opera) currently lack any border whatsoever. What you can do in this situation depends on how you deal with time and budget constraints, as well as how far you want to go with providing a common visual experience across browsers: some solutions may require more time than others.

For the sake of this article, I’ll show you two. None of them deals with rounded corners, in most cases they are just a visual refinement that adds nothing worth the effort; users of regressive browsers will just see squared borders and it is unlikely it will impair their experience with the website.

Solution the first

When looking for solutions, context always matters. In the case of Facebook, whitespace occupies a high percentage of screen real estate to save users from any distraction and allow for a comfortable reading. Therefore, dialog borders will, most of the time, come on top of a white background. Why not pick up the color formed by the combination of a semi-transparent black and white, that is, a soft grey? Let’s do it:

.dialog { 
  border: 10px solid rgb(127, 127, 127);
  border: 10px solid rgba(0, 0, 0, .5);
  -webkit-border-radius: 8px;
  -moz-border-radius: 8px;
  border-radius: 8px; }

The result is pretty satisfactory. By taking advantage of how the CSS parser deals with unknown properties or values, it’s straightforward to (1) specify a value that will get parsed by IE and Opera, and (2) specify a value that will be ignored only by them.

This solution is a no brainer and takes seconds to implement.

Solution the second

If transparency is absolutely needed, you’ll have to fall back to using a PNG image. But, wait? It’s impossible to use images for borders! That’s right (unless you want to use the border-image property introduced in CSS3, that is), we’ll have to get rid of the border here and use some padding instead:

.dialog { padding: 10px; background: url('dialog-bg.png'); }

Straightforward as well, but we’re not yet done. We don’t want to lose the RGBA borders and rounded corners that work so well in progressive browsers, thus the declaration above needs to be hidden from them and be served only to Internet Explorer and Opera.

In the case of IE, it’s easy to do it using conditional comments:

<!--[if IE]>
Only IE will see what is put here
<![endif]-->

Neat.

With Opera, however, there is no such mechanism. But it is rather easy to fall back to some user-agent sniffing technique, especially one called Conditional-CSS.

We’re finally done! You can check the results here.

Conclusion

When faced with a problem, especially when developing websites, it’s easy to fall into the trap of obvious solutions that come from the ages, where dealing with legacy browsers that did not support CSS was an everyday challenge. But in order to provide the best experience to everyone we have to get rid of these and start using all the powerful tools Web Standards given us in a creative and future-oriented manner. I hope this example shows you how it can be achieved rather easily.

What’s your opinion? Is there any topic you’d want to see covered? I’d welcome any suggestion.