First of all, to find out what mincss is read this blog post which explains what the heck this new Python tool is.

My personal website is an ideal candidate for using mincss because it uses an un-customized Bootstrap CSS which weighs over 80Kb (minified) and on every page hit, the rendered HTML is served directly from memcache so dynamic slowness is not a problem. With that, what I can do is run mincss just before the rendered (from Django) output HTML is stored in memcache. Also, what I can do is take ALL inline style blocks and all link tags and combine them into one big inline style block. That means that I can reduce any additional HTTP connections needed down to zero! Remember, "Minimize HTTP Requests" is the number one web performance optimization rule.

To get a preview of that, compare https://www.peterbe.com/about with https://www.peterbe.com/about3. Visually no difference. But view the source :)

Before:
Document size: Before

After:
Document size: After

Voila! One HTTP request less and 74Kb less!

Now, as if that wasn't good enough, let's now take into account that the browser won't start rendering the page until the HTML and ALL CSS is "downloaded" and parsed. Without further ado, let's look at how much faster this is now:

Before:
Waterfall view: Before
report

After:
Waterfall view: After
report

How cool is that! The "Start Render" event is fired after 0.4 seconds instead of 2 seconds!

Note how the "Content Download" isn't really changing. That's because no matter what the CSS is, there's still a tonne of images yet to download.

That example page is interesting too because it contains a piece of Javascript that is fired on the window.onload that creates little permalink links into the document and the CSS it needs is protected thanks to the /* no mincss */ trick as you can see here.

The code that actually implements mincss here is still very rough and is going to need some more polishing up until I publish it further.

Anyway, I'm really pleased with the results. I'm going to tune the implementation a bit further and eventually apply this to all pages here on my blog. Yes, I understand that the CSS, if implemented as a link, can be reused thanks to the browser's cache but visitors of my site rarely check out more than one page. In fact, the number of "pages per visit" on my blog is 1.17 according to Google Analytics. Even if this number was bigger I still think it would be a significant web performance boost.

UPDATE

Steve Souders points out a flaw in the test. See his full comment below. Basically, what appears to happen in the first report, IE8 downlads the file c98c3dfc8525.css twice even though it returns as a 200 the first time. No wonder that delays the "Start Render" time.

So, I re-ran the test with Firefox instead (still from the US East coast):

Before:
WebpageTest before (Firefox)
report

After:
WebpageTest after (Firefox)
report

That still shows a performance boost from 1.4 seconds down to 0.6 seconds when run using Firefox.

Perhaps it's a bug in Webpagetest or perhaps it's simply how IE8 works. In a sense it "simulates" the advantages of reducing the dependency on extra HTTP requests.

Comments

Post your own comment
Rene Dudfield

Very cool! <3 it :)

There'd be a much bigger audience for it if it came as a script, rather than tied up in Django stuff. Well, at least then I could use it ;)

Have you tried it on other frameworks, or websites apart from bootstrap ones?

Peter Bengtsson

mincss has nothing to do with Django. Did you see this? http://www.peterbe.com/plog/mincss

I have, for example, not used it on my one-page-tonnes-of-javascript *app* http://aroundtheworldgame.com because it's just too much Javascript dependent.

Rene Dudfield

Aha! No, I missed that link. Brilliant :)

Joe Ciskey

The obvious feature to add is taking a list of pages, applying the script to each of them, and then aggregating the entire result so that you have a site-wide CSS file that can be cached by browsers. I might just fork this and give it a try.

Peter Bengtsson

It already exists. The API is built such that you feed it URLs till your done then call the `.process()` method to start the calculation. For example:

  >>> from mincss.processor import Processor
  >>> p = Processor()
  >>> p.process_url('http://example.com/page1.html')
  >>> p.process_url('http://example.com/page2.html')
  >>> p.process()

However, if you do that, the `p.inlines` will be confusing since you won't know which URL it came from. There's a shortcut to when you just have 1 single URL to worry about and that's to use `.process()` directly:

  >>> from mincss.processor import Processor
  >>> p = Processor()
  >>> p.process('http://example.com/page.html')

Or you can actually do this too:

  >>> from mincss.processor import Processor
  >>> p = Processor()
  >>> p.process('http://example.com/page1.html', 'http://example.com/page2.html')

Messing around with doing one page at a time and using inline is more advanced and perhaps something just for those who want the absolutely fastest.

Steve Souders

Hi, Peter. It's fun to read about how mincss is making sites faster. I have one issue with your results, however. You mention how the page starts rendering much sooner. If we look at the "before" results ( http://www.webpagetest.org/result/130121_H_1MQ/1/details/ ) we see that rendering is blocked waiting for c98c3dfc8525.css. The weird thing is we can see that c98c3dfc8525.css is downloaded TWICE (see requests #2 & #12). It would be great if you could figure out why this happened (IE8 anomaly?) and re-run to get more comparable results.

Peter Bengtsson

It appears to respond with a 200 the first time so I honestly don't know what's going on.

I'll re-run the tests with a sane browser and see if it's reproduce-able.

Peter Bengtsson

Updated the blog post.

Warren

I can't get it to even process a page. The traceback is not very helpful.

>>> p.process('http://localhost:8001')
TROUBLEMAKER
u'a[href^="javascript'
TROUBLEMAKER
u'a[href^="javascript'
TROUBLEMAKER
u'a[href^="javascript'
TROUBLEMAKER
u'a[href^="javascript'
TROUBLEMAKER
u'a[href^="javascript'
TROUBLEMAKER
u'a[href^="javascript'
TROUBLEMAKER
u'a[href^="javascript'
TROUBLEMAKER
u'a[href^="javascript'

Peter Bengtsson

That's not a traceback. It's not an exception. It's just a print statement that the underlying CSS parser struggled with certain selectors.

Your email will never ever be published.

Related posts

Go to top of the page