Skip to content

The CSS bits of Progressive Enhancement

At work the other day we were talking about Progressive Enhancement and feature phones, particularly in terms of CSS. The feature phones part of the chat led me to write up a short Dos and Don’ts of Feature phone design (written for designers more than developers). The PE part of the chat made me scribble up the following pictures.

Every web page looks like this. A base of HTML, with CSS layered on top, and JS layered on top of that. It’s a triangle because the balance should mostly be like that: lots of HTML, quite a lot of CSS, and as little JavaScript as possible.

Practically speaking, we chop things up a bit more than this, though.

First we load in a small file of simple CSS. Then we do some PE fancy magic testing stuff and load in Fancy CSS for fancy browsers.

Actually, though, even the fancy CSS file is splitty too. Inside the fancy CSS file we do more little tests and give fancier browsers fancier styles.

Technical details

The initial split between basic and fancy CSS files is done using a media query on a link element.

The basic CSS is loaded like this:

<link rel="stylesheet" href="/css/style.css">

All browsers get this stylesheet (and it contains simple CSS rules that all browsers will understand). The fancy CSS should be loaded like this:

<link rel="stylesheet" media="screen and (min-width: 20em)" href="/css/enhanced.css">

Since it’s qualified with a media query, it should be the case that only browsers that understand that media query (goodbye old Internet Explorer, and many older phones) load that stylesheet. However, Scott Jehl's tests have shown that this isn't the case: browsers are greedy and download all the stylesheets, even ones they will never use!

That's not so great. Ideally we'd like to improve Front-end performance by using Filament Group's loadCSS to asynchronously load our enhanced stylesheet (so that it doesn't block page render), but that would mean everyone downloads every stylesheet. Instead we use Scott Jehl's eCSSential. This lets us load the CSS file asynchronously (yay, performance!), and use matchMedia to test for (min-width: 20em) with JavaScript. Testing with matchMedia in JavaScript rather than than a media query on a link element works: browsers only download the stylesheets they need. (Of course, we also provide a no JavaScript fallback in a <noscript> tag, in case something goes wrong somewhere.)

You can see an example of this in action on my work in progress project, fufu (A future friendly front-end style guide that even caters for feature phones).

Gotcha: older Androids

The use of matchMedia has me a bit conflicted. Looking at matchMedia on caniuse.com, we see that this means that Android versions less than 3 and Opera Mini users won't get the enhanced stylesheet. If we went the loadCSS route, some Android 2.* users would get the enhanced styles (which their browsers are capable on displaying), but we increase data costs for all users, because everyone loads all the stylesheets.