mattgadient.com

css blocking – wordpress and W3TC – how to get parallel downloads

It’s almost 2013, and I have to wonder why modern browsers still get tripped up over CSS stylesheets when it comes to blocking parallel downloads. Just to make sure we’re on the same page, I’m talking about this sort of thing:

CSS loads by itself. CSS and JS loading together CSS loads with 2 JS. The 3rd JS loads later with images.

As you can see (you can click for larger images, by the way):

  • in the 1st image, the CSS loads all by itself. Everything else is blocked until the stylesheet finishes. What an inefficient use of time!
  • in the 2nd image, things look a little better. The CSS and 2 javascript files are downloaded simultaneously. It’s a friendship made in HTML-land. All those images don’t start until the CSS finishes though (they’re blocked).
  • in the 3rd image… something looks a little off. One JS file started with the CSS, but the other one is still blocked just like the images! What gives?!

If you’re using WordPress (and to a lesser extent, W3 Total Cache), at least one of the above images probably describe your situation. Let’s face it, you’re reading this for a reason, right?

The really exciting part is that while looking at the waterfall might give you hints as to where you need to make changes, it’s just as likely to totally mislead you.

Lucky for you, I went through a lot of trial-and-error and got it all figured out. This is assuming your CSS is linked at the very top of your <head> section (which W3TC does if you make use of the minify part). For those who don’t use W3TC minify, if any/all javascript comes after the CSS link in your HTML you’re in the same boat anyway, so keep reading. Here’s the dealio:

  • The browser gets your html and breaks down all those downloads (css/js/images) into 2 types – for the sake of simplicity, we’ll call them get-now and get-after-css. I’m sure those aren’t the technical names, but they match up nicely with waterfall images.
  • Since your style.css is the first thing, it goes in the “get-now” section.
  • The browser keeps reading through the HTML and starts putting images it comes across into the “get-now” category until it hits a script. Any script. If you write “hello world” in some inline javascript it will stop putting images in “get-now” right then and there. It does’t matter whether the script it hit was blocking or non-blocking. Do not pass go, do not collect $100. It’s done putting images in the “get-now” bucket – any images that didn’t make it in will have to wait until later.
  • Next is where “blocking” scripts come into play. Sure, the browser has given up on all your pretty pictures, but if you have any scripts that are of the “blocking” type, the browser may as well get them over with. It searches the entire page and finds them. Blocking scripts are then added to the “get-now” bucket.
  • Now, everything in “get-now” starts to parallel download. This includes the CSS file, any “blocking” Javascript, and whatever images happened to be between your style.css and the script the browser ran into. Any remaining images and any scripts that happened to be “non-blocking” are put in the “get-after-css” bucket.
  • Once your stylesheet has finished downloading, the browser grabs stuff in the “get-after-css” category. That includes non-blocking javascript & the images that weren’t early enough to make it in “get-now”.

Putting it into context

Let’s look at the 1st image again and see what happened:

CSS loads by itself.

 

CSS was clearly the only thing in the “get-now” bucket. What actually happened here was this:

<head>
stylesheet
google analytics (javascript)
......</head>

After the stylesheet, it immediately hit a script in the head, so it didn’t reach any images. Even worse, because both javascript files were “non blocking” (google analytics and the site’s javascript), even they had to wait until the CSS finished. And one of them took a loong time to download – it would have been nice if it had started when the CSS did.

 

We’ll skip to the 3rd waterfall image now:

CSS loads with 2 JS. The 3rd JS loads later with images.

 

This one is very similar, except that the 1st Javascript you see is now of the “blocking” type. Which sounds bad, but is actually a good thing- it gets to be in the “get-now” bucket with the CSS.

 

So what’s ideal? Well… this:

CSS and everything else load at the same time.

 

Don’t those line up beautifully? No time is being wasted here!

 

So how do we get there?

Here’s the bad news. Your HTML has to look pretty much like this:

<head>
stylesheet
other-stuff (no scripts!)
</head>
<body>
other stuff (no scripts!)
images
images
scripts (javascript) at the end
</body>

And when I say no scripts, I mean it. Internal, external, blocking, nonblocking, doesn’t matter – the moment you have a script in there, every other image afterwards will go into the “get-after-css” category.

Now for the good news. While it can be tough, in many cases it’s possible to do. If you’re using WordPress, here are a few tips:

  1. View your website and hit “edit source”. Find the location of your scripts beforehand so that you know what you’re up against.
  2. Use the minify portion of W3 Total Cache to combine your .js files and choose “Embed before </body>”.
  3. If you access other external scripts (like some of the javascript Google hosts), or don’t to use want W3 Total Cache, there are quite a few JS minify plugins that will combine, minify & relocate your javascript. There’s also a plugin called “Javascript to footer” which is simple (it just relocates), and very old but still works as of WP3.5.
  4. If a certain plugin doesn’t work when it’s javascript is at the end, try another similar plugin. For example, while a number of lightbox/shadowbox plugins do not behave, some do. WP JQuery Lightbox comes to mind as one that works.
  5. If you’re creating a theme or are capable of editing yours, make clever use of <div> so that any sections of html that might contain some javascript (Adsense, anyone?) come as close to the end of the HTML as possible. Even if in the end your scripts still block a few images, a few blocked is better than all blocked.

If things get tough, be creative. I haven’t tried it, but you could try throwing a few CSS rules in the <head> to load in a few style=”background-image:url”. If you can at least get all the javascript out of <head>, you could always try pre-loading your images as 1x1px images in an empty div as soon as the body starts.Where there’s a will, there a way.

 

Ok, so javascript is now at bottom with W3TC. Blocking vs Non-Blocking?

Both are essentially a double-edged sword.

 

Blocking:

When it comes to getting the javascript downloaded quickly (to do better in your page-speed tests!), blocking is the way to go. They’ll download in parallel with your style.css . And if your images are being blocked due to a script you can’t relocate, at least you’ll have *something* downloading along-side the CSS.

However, from what I understand, “blocking” has a side-effect – the browser may want to execute/run the javascript before it starts displaying the webpage to the user. Which means the user probably won’t see anything until the javascript has finished downloading.

 

Non-Blocking:

If you choose non-blocking, your .js files will be downloaded rather lazily (they won’t start until your style.css has finished downloading). Not so good for your page-speed tests.

That said, from what I understand (again), non-blocking scripts won’t “hold up” the page. Once all your CSS/formatting is in place, the browser should display your page for the user even if the javascript is still downloading in the background.

 

  • Great article.
    I’ll try to use it today to see the results

  • Thanks so much for this. Ive been scratching my head trying to sort this for along time.

    Ive got my w3 total cache css file parallel loading with images etc now, but would to recommend “defer” or “async” for Javascript?

    Thanks

    • Hey Mike,

      I’d experimented with both a couple months back but was running into issues where the fancybox/lightbox scripts I was using would only consistently work correctly with defer. Assuming for the moment that I’d had the option of both though, from what I understand, both will allow the javascript to download without blocking. Once downloaded, async should try to execute the javascript as soon as it has finished downloading, while defer should wait to execute it until after the rest of the HTML has been parsed. In theory, really complex javascript called early in the HTML that downloaded fast but took awhile to execute (say, a prime-number generator) would probably be best to defer so that the *execution* of the script doesn’t end up blocking the rest of the HTML from being parsed. In reality, most common javascript executes so fast that it shouldn’t really matter, so if the javascript affects visual content “above the fold” I’d be inclined to try async, and might just go with defer otherwise.

      All that being said, your best bet is to first try both and make sure your .js works fine with either. If that’s the case, do a few comparison checks for each on webpagetest.org with Chrome/FF or new versions of IE and see if you can spot any differences in page load time. If there’s no difference, the next thing to check against would be if it affects paint/render times (the video captures are probably the most helpful for those, having it fake a slow dial-up).