In his recent post on web standards and progressive enhancement, Zeldman notes:
When a site like Facebook stops functioning when a script forgets to load, that is a failure of education and understanding on the part of those who created the site.
This has me rethinking the way I’ve approached progressive enhancement.
How I do progressive enhancement
When I write scripts that hide or manipulate content on a page, I make all content visible by default, and use a feature test to add a
.js class to the
<body> element. I only hide and manipulate content when that class is present, esnuring that no one is ever prevented from seeing the content. (Learn more about how I use feature tests.)
Unfortunately, this can cause FOUC.
FOUC, or flashes of unstyled content, happen when markup is loaded before the styles of scripts that style it.
I load my scripts in the footer for better performance. Because no content is hidden or manipulated before those scripts load (progressive enhancement), visitors will often see the page build before them, with all of the drop-down navigation elements visible and tab content stacked on top of each other. Once the script loads, everything looks normal.
A simple way to avoid this is by putting the feature test up in the
<head> element, which is what I now do on all of the sites that build. Since it loads before any of the markup is painted, there’s no FOUC.
So we’re good, right? Well, not exactly…
Failure to Load
The Zeldman quote at the beginning of this piece identifies a giant hole in this approach. If a browser supports the appropriate API’s but fails to load a JS file, the content is hidden, but the script that would allow a user to manipulate and view it isn’t there.
I’ve encountered this countless times, especially on mobile devices where things just time out because they take too long. Not being able to view the content you want is a terribly frustrating user experience—one far worse than a momentary flash of unstyled content.
As Jake Archibald says:
On Building Escalators
Unfotunately, it feels like progressive ehancement and FOUC are a bit at odds with each other. You could just load all of your scripts in the
<head>, but then your left with flashes of no content, which is even worse.
For now, I plan on updating all of my scripts to run the feature test as part of the JS file itself. It will introduce some FOUC, but if the file doesn’t download, users can still access the content. If anyone can come up with a better solution—one that removes FOUC and ensures users always have access to the content—let me know!
Leave a comment or contact me on Twitter at @ChrisFerdinandi.
I hardcode a
.no-js class to
<head> element then replace it with a
.js if JS is enabled (either use Modernizr or custom 1 liner in the
<head>). I then style my page expecting JS to be enabled and use the
.no-js class to override any styles that are needed when JS is disabled.
@Chris Pearce – That’s pretty similar to what I do (though I assume no JS by default). I guess my biggest concern is that you’re testing with one file that has no visibility to whether or not the other one has loaded. So you can end up in a situation where the browser supports JS, but the needed file failed to download and so content is inaccessible to the user.
I’m finding that preventing FOUC is at odds with that challenge.
(PS: I added the missing text back in to your original comment for you.)