UX Design and Development course

Progressive Enhancement with CSS

A follow-up article to Understanding Progressive Enhancement by [Aaron Gustafson]

source http://alistapart.com/article/progressiveenhancementwithcss

In the previous article in this series, we covered the basic concept of progressive enhancement; now, we can begin discussing how to use it. There are many ways to integrate progressive enhancement into your work using Cascading Style Sheets (CSS), and this article will cover a few of the biggies and get you thinking about other ways to progressively enhance your sites.

In this article, Aaron follows up the Peanut M&M analogy with how you can apply these principals to CSS. The article includes:

  • Style sheet organization
    • Use multiple stylesheets
    • Working with alternative media types
  • How to deal with IE6
  • Other considerations

Written in 2008 - techniques have changed

There are great basic thoughts in this article, but there are specific techniques in here that should be completely ignored.

These techniques are sound and are well worth understanding, but keep in mind that this article was written in 2008.

Individual style sheets

The section about breaking your style sheets into individual concerns is a great technique to understand and in many ways very practical. When getting to understand these concepts, it is perfectly acceptable to create these individual style sheets and make each one an individual <link> in the <head>. When you get closer to production ready code, techniques like pre-processors and minifiers will come into play.

And ... we don't have to worry about Netscape 4 any longer and the use of @media in CSS is HIGHLY DISCOURAGED!!! It is a huge performance killer and should be wiped off the face of the earth.

Browser support

DO NOT use conditional comments! In the context of this article the use of conditional comments to bring in specific style sheets per version of IE is an outdated concept.

New tools have become available since, including Modernizr, which changes the way that we think about 'feature' support our code.

In Aaron's article, he speaks of using conditional comments, like the following:

<!--[if lte IE 7]>
<link rel="stylesheet" type="text/css" href="ie7.css" />

<link rel="stylesheet" type="text/css" href="ie6.css" />

So, if someone comes to this page in IE7, they will get the fixes I have applied within, but if they come in a newer version ...

Ironically, the technique outlined in this article is the very essence of graceful degradation.

Simple feature support

In the article, there is a very simplistic approach to this where he simply adds a feature that is not supported by legacy browsers, is supported by new browsers and for the browsers that do not support the feature, it's a non-breaking issue.

For example, using CSS generated content:

label:after {
  content: ":";

The idea here is, if the browser supports it, then display it. If it doesn't, oh well. This technique greatly depends on your creative and content teams.

A few years ago, this was not acceptable and UI/UX needed to be 100% identical between browsers, new and old. This way of thinking resulted in endless hours wasted building JavaScript polyfills and other techniques.

Device enhancement

In the article he speaks of not using the media type in the <link> element of the page. Depending on how far down you have to support mobile devices, this may be the very tool you use.

For example, you are creating a site that needs to support 'feature phones'. For the most part, feature phones do not support modern media types. Much like how you can construct a media query in CSS, you can do the same at the <link> level as well.

The concept here being, you will create a standard baseline CSS that any device that supports HTML and CSS will render. These are core concepts in typography and layout. It's when you begin to encounter devices that start understanding the advanced media types that more complex resources become available to the user.

<!-- Loads for all devices -->
<link rel="stylesheet" href="core.css">

<!-- Loads at the mobile set breakpoint -->
<link rel="stylesheet" type="text/css" href="mobile.css" media="only screen and (min-width: 600px)">

This is a great technique and one that is used by many major online publications with a large presence. But these techniques come with their own complexity.

Progressive Enhancement w/Modernizr

With the coming of Modernizr, the previous techniques are considered out-dated. The concept of progressive enhancement is still openly encouraged, but I would argue that you write code from the perspective that 'if this feature is supported, then do this ...'

Let's take for example @font-face. Using Modernizr we can either go for graceful degradation or progressive enhancement. For the sake of argument, let's illustrate the both.

In the following example, I will use graceful degradation, commonly called a 'fallback':

h1 {
  font-family: 'Wire One', arial, serif;
  font-weight: bold;
  font-size: 48px;
  letter-spacing: 1px;
  text-transform: uppercase;

/* no-faceface fallback */
.no-fontface h1 {
  font-family: Arial, Helvetica, sans-serif;
  font-weight: normal;
  font-size: 30px;
  letter-spacing: 0;
  text-transform: none;

In this example, I am specifically stating that for all modern browsers will use this CSS class correctly, but for those that do not support this feature, here is alternative code.

Progressive enhancement on the other hand, would be the complete opposite.

h1 {
  font-family: Arial, Helvetica, sans-serif;
  font-weight: normal;
  font-size: 30px;
  letter-spacing: 0;
  text-transform: none;

.fontface h1 {
  font-family: 'Wire One', arial, serif;
  font-weight: bold;
  font-size: 48px;
  letter-spacing: 1px;
  text-transform: uppercase;

What this is saying is, the standard look of the site is going to use Arial, but when the site supports the @font-face feature then use 'Wire One'.

The issue with this last statement is that without the @font-face test, your preferred UI code will fail. But let's think about that for a second. If the test does not run, then there is a good chance that JavaScript is not supported and then there is a good chance that CSS3 features like @font-face are not supported as well.

The concept of progressive enhancement is the idea of writing future friendly code that is not at the expense of the current state of things. But when using a tool like Modernizr with CSS, the fine art of progressive enhancement over graceful degradation is a slow dance.

Modernizr going past the CSS

In essence, you can use Modernizr to conditionally load CSS via the same testing framework that Modernizr provides using the Modernizr.load feature. You could do something like the following:

Modernizr.load("stylesheet/touch.css", [
    test : Modernizr.touch,
    yep : [ 'javascript/touchscroll.js', 'javascript/ipad-scroll.js', 'javascript/mobile.js' ],
    load : [ 'javascript/ipad-default.js' ] // No need to specify this in 'yep' too

Modernizr is build on the yepnopejs which is designed more for conditionally loading polyfills versus CSS, so there may be slight flickers in your UI with this technique.

Another option to achieve this is to use Require.js as a solution.