Back when I was still actively into speaking at public events (way, way back, something like year and a half ago (which strangely roughly coincides with the time I joined Facebook, hmmm (hmm? (huh? what's with the parentheses? sure all of them are closed at this point?)))) I remember showing this slide:
The reason I'm bringing it up now is this experiment I saw today by Scott Jehl.
LINK elements with non-applicable
media attribs, such as
tv, too much
min-width and pixel ratio of 6 among others:
<link href="inc/tv.css" rel="stylesheet" media="tv"> <link href="inc/min-width-4000px.css" rel="stylesheet" media="(min-width: 4000px)"> <link href="inc/min-device-pixel-ratio-6.css" rel="stylesheet" media="(min-device-pixel-ratio: 6)">
And just for the fun of it, why not a
<link href="inc/nonsense.css" rel="stylesheet" media="nonsense">
Scott observed that (with one happy Opera nonsense exception) all browsers will load all this junk, all this CSS that they don't need.
(BTW, Opera 11.64 loaded nonsense css for me too)
Having recently remembered how browsers block rendering because of print stylesheets, I speculated that all the nonsense media will also block rendering. Unfortunately I was right.
So not only browsers download useless bytes, but they also block the rendering of the page (or block
window.onload, or both) until all the crap is downloaded. And by blocked rendering I mean showing a white page of death. Most browsers wait until all CSS is loaded because they don't like doing extra layouts and painting (except Opera).
Here's a test page for you to try:
all with your media query of choice, hit Enter and weep.
This test page loads css with delay: css1 delayed 5 seconds and css2 delayed 10 seconds. The HTML is:
<link rel="stylesheet" href="css1.css.php" type="text/css" media="screen" /> <link rel="stylesheet" href="css2.css.php" type="text/css" media="<?php echo $YOUR_MEDIA_QUERY; ?>" />
The correct browser behavior should be:
1. load only the CSS you need
3. fire onload
0. render if step 1. takes too long
Instead, randomness ensues: Firefox treats us to a white page for 10 seconds while downloading nonsense. Chrome takes 15 seconds to fire onload. (see the print CSS post for more)
So what are we to do? First, understand...
The evil that CSS do
- Browsers (except Opera) block rendering until all screen CSS arrives. With the worst possible experience: white page.
- Browsers download CSS they don't need, e.g. print, tv, device-ratio... And most browsers (except Opera and Webkit) block rendering because of these too
- Sometimes CSS blocks the other downloads too (not just block rendering, but block images and scripts that follow):
- when followed by an inline SCRIPT
- when it's a CSS in conditional comment for IE
The critical path
But I argue that CSS is not only on the critical path, it is the critical path. And because it's a jungle (network, 3g, edge) out there, anything on the critical path will fail. Guaranteed.
What's left on the critical path is CSS. Not only the page is ugly without CSS, we can live with that, but there is no page without CSS because the browser waits and waits and takes forever to timeout showing us a blank white page.
Get the CSS out of the way
So if you worry about performance, you should get the CSS out of the way as soon as possible. Get off the critical path. Make CSS small, minify, compress, load from the same hostname even (no DNS) and inline, if small enough. Yup, inline.
Take a look at these highly optimized experiences...
Look ma, no CSS!
Yes, these pages make no CSS requests whatsoever.
If your CSS is not puny enough to be all inline (Guy has some observations on what puny means) it should at least be a single file, way at the top of the document, with the first flush. Just get it over with. Your users will love you and praise you and use words like smooth and snappy.