Autoptimize CSS defer switching to loadCSS (soon)

Historically Autoptimize used its own JS-implementation to defer the loading of the main CSS, hooking into the domContentLoaded event and this has worked fine. I knew about Filament Group’s loadCSS, but saw no urgent reason to implement it as I saw no big advantages vs. my homegrown solution. That changed when criticalcss.com’s Jonas contacted me, pointing out that the best way to load CSS is now using the rel="preload" approach, which as of loadCSS 1.3 is also the way loadCSS works;
<link rel="preload" href="path/to/mystylesheet.css" as="style" onload="this.rel='stylesheet'">
As rel="preload" currently is only supported by Chrome & Opera (both Blink-based), a JS polyfill is needed for other browsers which uses loadCSS to load the CSS. Hopefully other browsers catch up on rel="preload" because it is a very elegant solution which allows the CSS to load sooner then with the old code while still being non-render blocking. What more could one which for (“Unicorns” my 10yo daughter might say, but what does she know)?
Anyways; I have integrated this new approach in a separate branch on GitHub, you can download the zip-file here to test this and all the other fixes and improvements since 2.1.0. Let me know what you think. Happy preloading!

Should you inline or defer blocking CSS?

CSS codeYou care about web performance and so you dutifully aggregate and minify your CSS. But then a couple of months ago Google PageSpeed Insights (for mobile) started identifying CSS as a render blocking resource and so you wonder if you should you inline your CSS, or even defer loading it. Based on tests executed on a multi-site WordPress installation, deferring CSS is not the best idea just yet, but inlining might be worthwhile! Read on for the hard numbers and other details.

The test-setup

  • 4 test-blogs on a multi-site WordPress instance
  • using the Expound theme (which is interesting because its main stylesheet imports 2 other CSS-files)
  • using Lite Cache for page caching (new WordPress page caching plugin by the Hyper Cache author)
  • the same content was imported on all 4 blogs
  • all 4 had Autoptimize HTML & JS optimization active
  • the difference was in the Autoptimize CSS settings, where:
    • blog 1 had no CSS optimization at all (baseline )
    • blog 2 had standard CSS aggregation and minification, linked in head
    • blog 3 inlined the optimized CSS
    • blog 4 deferred the optimized CSS
  • each blog was tested on webpagetest.org‘s Amsterdam node on a DSL-profile using IE9 and doing 9 test-runs on one specific blogpost with contained a 16KBimage (I excluded favicon.ico as it seemed to pollute results)
  • each blog was analyzed by Google PageSpeed Insights for both mobile & desktop

The results

test report urlfirst bytestart renderdoc completefully loadedmobile pagespeeddesktop pagespeed
1. no css optimization140212_Z1_MKN0.299s2.246s2.221s2.221s7992
2. optimized CSS linked140212_H7_MKP0.239s0.608s1.390s1.390s9197
3. optimized CSS inlined140212_A3_NJA0.232s0.348s0.658s0.658s9999
4. optimized CSS deferred 140212_8J_P1G0.248s0.357s1.034s1.034s9995

The conclusions

Based on these tests (your mileage may vary, always test your results):

  • deferring all CSS is useless, performance is worse, desktop PageSpeed score is (slightly) lower and there is a “flash of unstyled content” between the rendering of the page and the application of the CSS.
  • Inlining CSS yields the best results both from a page speed and PageSpeed perspective. Although the base HTML is larger as it has the CSS payload, this has almost no impact in this specific context and rendering is almost instantaneous. Off course in a context where multiple other pages from the same site, with the exact same CSS would be loaded, the impact would be significant. Hence inlining CSS is especially interesting for sites with a low pageviews/ visitor ratio.

The future; inline + defer

Deferring CSS may seem pretty useless, but the sweet spot may just be inlining base CSS (everything needed for initial rendering above the fold) and deferring everything else. This is what CSS optimizing tools should focus on in 2014 and you can certainly expect something along these lines in one of the next major Autoptimize releases (although diehards can already test this approach).

Coming up: Autoptimize 1.8 with API and inlined CSS

I’ve been working on a new Autoptimize version over the last couple of weeks and consider it largely finished now. The following features are in:

  • Optionally inline all CSS as suggested by Hamed (warning: can result in improved pagespeed-score but lower page speed! I’ll write a blogpost about when to use and not to use this one shortly)
  • Simple API Set of filters to provide a simple API (including example code) to change Autoptimize behavior to
    • conditionally disable Autoptimize on a per request-basis
    • change the CSS- and JS-excludes
    • change the limit for CSS background-images to be inlined in the CSS
    • define what JS-files are moved behind the aggregated one
    • change the defer-attribute on the aggregated JS script-tag
  • Improvement: updated upstream CSS minifier
  • Improvement: switch default delivery of optimized CSS/JS-files from dynamic PHP to static files
  • Improvement (force gzip of static files) and bugfix (force expiry for dynamic files, thanks to Willem Razenberg) in .htaccess
  • Bugfix: fail gracefully when things go wrong (e.g. the CSS import aggregation gone haywire resulting in empty aggregated CSS-files that was reported by Danka)
  • Bugfix: stop import-statements in CSS comments to be taken into acccount as seen by Joseph from blog-it-solutions.de
  • Bugfix: fix for blur in CSS breaking as reported by Chris of clickpanic.com
  • Updated translations

Some more testing and a couple of translations are still to be updated and we’re good to go for a release early January. You’re welcome to join in on the fun off course; download the test-version here and let me know what works and -more importantly- what is broken!