Oct 21, 2009

Really parallel CSS files - possible?

For about a year we aredealing, optimizaing, fighting with including background images into CSS files. This technique was successfully implemented in Data:URI [CSS] Sprites (and in Web Optimizer last week), but we faced there IE7@Vista bug (Aptimize doesn't handle it good , just skips any caching, it's terrible). But this post isn't about such bugs.

Parallel CSS files and FOUC

Everybody who deals with web pages performance optimization should know about FOUC - Flash Of Unstyled Content. Every browser tries to prevent such behavior (maybe except Opera), they delay on showing any picture on screen before they are sure to show 'styled' content. Even if CSS files are being loaded in 2, 3, 4, and more channels. It doesn't matter. The whole page will shown only after all CSS files will be loaded (and if there are any scripts - the situation will be even worse, blocking scripts in action).

No Parallel CSS files?

Actually, no... It's possible to force browser to render the page, and then add any CSS file. It's tricky but it exists. Why should we use this way?

data:URI (or mhtml) can be very large in size. Generally (even with compression) it's about 2-5x larger that CSS rules themselves. SO we can render the page about 2-3 times faster only with this technique!

Magic, magic!

After a long testing with various ways to inject CSS file to the document the following approach was invented. We can add one CSS file (with rules) to the very beginning of the page. Then we should add the second CSS file (with resources), but where? And how to load it 'true unobtrusively'?

We can add a bit scripting (inside head) which will:

  1. Hide initial CSS file from browsers with enabled JavaScript.
  2. Add this file to loading query on DOMready event.
  3. And degrades gracefully for browsers with disabled JavaScript (or broken for some reasons).

OK. The first point is simple:

<script type="text/javascript">
document.write("\x3c!--");
</script>
<link type="text/css" href="resource.css" rel="stylesheet"/>
<!--[if IE]><![endif]-->

After this CSS file there is conditional comment for IE, it plays as just closing comment for JavaScript one, or just a junk code for browsers with JavaScript disabled.

The second point isn't very hard:

<script type="text/javascript">
function _weboptimizer_load(){
load_our_css_here();
}
add_event('dDOMready', _weboptimizer_load);
</script>

So after browser renders the content in browser - we start to load additional CSS file with background images.

The third point has been already implemented in the first piece of code.

Browsers' support?

This code plays well in all browsers. A number of them tries to get this resource file earlier than DOMready event is called. But in this case content is rendered as soon as the first CSS file (only raw rules) has been loaded. So everything seems to be OK.

This approach is already in Web Optimizer since version 0.6.3. Option is called 'Load images on DOMready event'.

2 comments:

  1. A little bit off topic but CS sprite vs. data:URI must be tested very carefully against the server environment.

    I have one page where waiting for the (shared) server is a main issue. The solution with wbo is to have as many local files as possible in one file. data:URI has proven to be perfect and I could reduce the whole load to two files. Page loads under two seconds now. Before the waiting times for the single files summed up to incredible 7-14 seconds. Disadvantage: Big header logo looks funny because of some little extra space in IE<=6 but visitors don't care.

    My personal Textpattern page on a different shared hosting solution is reacting pretty fast and I am using a different approach: Fast page load, small and fast CSS load, small CSS sprite (only needed and loaded on homepage) and header logo.jpg excluded from CSS sprite. This request queue works very smooth and the file sizes are much better optimized than the above data:URI example.

    Which options to activate in the web optimizer swiss army knife tool kit is sometimes not as easy as it may look.

    ReplyDelete
  2. document.write() doesn't exists in «real» XHTML (with proper content-type header like application/xhtml+xml) if it does matter for someone.

    ReplyDelete