CSS minifier and alphabetiser

2009-08-27 – 5:27pm

Update: This project is now hosted on GitHub: http://barryvan.github.com/CSSMin/

There are quite a few CSS minifiers out there, which can bring the raw size of your CSS files down substantially. Very few of them, however, will also optimise your CSS for gzip compression. To that end, I’ve written a small Java application that will read in a CSS file and output its contents to stdout or another file in a format that’s optimised for gzipping.

The problem

A file will be most compressed when there are many recurring strings in the file. This means that when writing CSS files, this code:

.pony {
border: solid red 1px;
font-weight: bold;
}
.lemur {
border: solid red 1px;
font-weight: normal;
}

will be better-compressed than this:

.pony {
border: solid red 1px;
font-weight: bold;
}
.lemur {
font-weight: normal;
border: red solid 1px;
}

What it does

Specifically, my CSS minifier will perform the following transformations on the file:

  • All comments are removed.
  • The properties within all selectors are ordered alphabetically.
  • The values for all properties are ordered alphabetically.
  • All unnecessary whitespace is removed.

By way of example, the following CSS snippet:

body {
padding: 8px;
margin: 0;
background-color: blue;
color: white;
font-family: "Trebuchet MS", sans-serif;
}

h1 {
margin: 0;
padding: 0;
font-size: 200%;
color: #0F0;
font-weight: bold;
}

p {
margin: 0 0 2em;
line-height: 2em;
}

would be formatted to:

body{background-color:blue;color:white;font-family:"Trebuchet MS",sans-serif;margin:0;padding:8px;}h1{color:#0F0;font-size:200%;font-weight:bold;margin:0;padding:0;}p{line-height:2em;margin:0 0 2em;}

Compression results

A (very) large real-world CSS file of 78.2KB has a minified size of 63.7KB, which is a size decrease of nearly 20%. GZipping these two files, the un-minified file is reduced to 13.2KB, whilst the minified file weighs in at just 11.5KB — nearly 13% smaller.

Clearly, removing unnecessary whitespace and reordering the contents of the CSS selectors can greatly improve the compression of your CSS files, and thus make your pages deliver more quickly.

Comparison with YUI CSS Compression

As you can see in the chart below, the YUI compressor manages to make the original file around 1KB smaller than my minifier. However, when the two minified files are gzipped, my compression results in a file that is 11.5KB in size, whilst YUI only reduces down to 11.8KB.
A chart comparing YUI's CSS compression and mine

Download

The source for this applet is available freely, and is a single Java file. It’s not particularly pretty, because I knocked this together in about half an hour.
Download
License: Mozilla Public License (In other words, do whatever you like with it. Credit is greatly appreciated, but not required.

Usage

First, if you haven’t done so yet, compile the code:

# javac CSSMin.java

Then, you can call the minifier by running

# java CSSMin in.css [out.css]

If you do not specify an output file, the resultant CSS will be printed to stdout (and can then be redirected as you wish).

Contact

If you have any questions or comments about this app, or if you find a bug or some weird behaviour, just comment on this post, and I’ll see what I can do.

If you find this utility useful, let me know! If you want to extend it, you’re free to do whatever you like with it, as it’s under the MPL. It would be nice, though, if you dropped me a line to let me know what you’re doing with it. :)

Future work

  • Replace “0[px,em,%,etc]” with “0″.
  • Replace “0 [0 [0 [0]]]” with “0″.
  • Replace “0.6″ with “.6″ wherever possible.
  • Replace all “rgb(64, 64, 64)” with “#404040″.
  • Shorten colours from #112233 to #123 wherever possible.
  • Remove all empty rules.
  • Ordering of property valus according to the CSS spec, not just alphabetically.
  • A cleaner interface, including the ability to stream and process from stdin.
Oliver Nassar
2009-08-28 – 2:01 am

Very cool. Never seen this done :)

2009-08-28 – 9:19 am

Thanks Oliver! I’ve updated the post with a chart comparing my minifier against YUI’s, both in terms of raw output size and final gzipped size.

Ray Cromwell
2009-08-28 – 10:03 am

You may want to experiment with something like this on really large CSS files:

http://timepedia.blogspot.com/2009/08/on-reducing-size-of-compressed.html

Re-ordering based on edit-distance.

2009-08-28 – 10:20 am

Yes, you’re right, Ray, that could result in much more significant compression performance. The only difficulty with implementing it for CSS files is that I would have to then have some knowledge of the document that the CSS is to be applied to, to ensure that rules cascade correctly.

Whereas in Javascript functions can largely be reordered without any problems, because the script does not depend on the document order, CSS uses the order that items appear in the document to determine whether they are overridden.

Still, I will definitely investigate this further — I am sure that there are some optimisations that can be done in this direction quite safely.

2009-08-29 – 6:37 am

Nice work. It seems to me this would be better as a patch to YUI — the YUI compressor has already taken care of a lot of the problems and micro-optimizations and edge cases of CSS through minor bugfixes, so it doesn’t make sense to re-invent the wheel. YUI Compressor is open-source and already adopted by a lot of people — what do you think?

2009-08-30 – 4:52 pm

@Andrew: I understand what you’re saying. The difference, though, is that the YUI CSS compressor is essentially a string-replacement system, whereas my optimiser actually parses the CSS file. It’d essentially be a complete rewrite. :) That being said, I have looked through the code of the YUI compressor, and I’ve certainly not been shy in realising that I’d missed an edge case or whatever.

There’s still a lot of work to be done on this, but hopefully it’ll become a nice robust CSS minification package over time.

2009-09-01 – 9:54 pm

Nice work and I enjoyed the post. I discovered this blog through Ajaxian and have just subscribed to it’s RSS feed :)

One thought of potential concern, I know that some CSS orders properties within a selector in a certain order so that IE will do the correct behaviors. I believe in some cases property order DOES matter.
I haven’t researched this further, but I seem to recall this being the case.

I personally will probably continue to use the YUI CSS compressor as it’s already part of my build process, right alongside using it’s JS compressor.

I look forward to reading future blog posts from you :)

2009-09-01 – 10:03 pm

Thats interesting. I am pretty sure this helps, but how about something like this:

html{
height:100%;
max-height:100%;
/* hide overflow:hidden from IE5/Mac */
/* \*/
overflow: hidden;
/* */
}

or any other css hacks?

Aike
2009-09-01 – 10:54 pm

i am not sure, but isn’t grouping by selector better?
like:

.pony {
border: solid red 1px;
font-weight: bold;
}
.lemur {
border: solid red 1px;
font-weight: normal;
}
——
to:

.pony, .lemur {
border: solid red 1px;
font-weight: normal;
}

2009-09-01 – 11:51 pm

Could you publish your test CSS file?

@Fabian: Minify’s CSS compressor preserves many comment hacks.
Can you publish your test CSS file so we can compare other algorithms? :)

2009-09-01 – 11:52 pm

@Fabian, disregard the last sentence. I meant to remove it.

2009-09-02 – 12:43 am

Is it the fact that the properties are in alphabetical order helping compression?

Or just that the properties are in the same order throughout all the selectors?

2009-09-02 – 1:34 am

Nice idea about reordering properties to improve gzipping. I don’t think a fixed ordering (e.g. alphabetical) will be optimal, however. Suppose I have the following:

body {
color: blue;
border: 1px solid red;
padding: 10px;
}

div {
border: 1px solid red;
padding: 10px;
}

Changing the order of border and color in the body will decrease the repetition and so increase the gzipped size.

An optimization technique (something in the realm of genetic algorithms) could be used to determine an optimal ordering which would be unique to the particular source file.

2009-09-02 – 9:04 am

@Robert: Thanks for the subscription! Glad you’re enjoying the blog. :)

At the moment, everything is just alphabetised, so if you rely on property order for something, the process may well break it.

2009-09-02 – 9:06 am

@Fabian: At the moment, the system will strip out any and all comments, without regard for their use in hacks, so your example will result in the “overflow: hidden” not being hidden. :/

2009-09-02 – 9:07 am

Yes, grouping by selector would be much better — it’s actually an optimisation that I’ve considered in the past. In the example, though, your final output would have to be something like

.pony, .lemur {
border: solid red 1px;
font-weight: normal;
}
.pony {
font-weight: bold;
}

2009-09-02 – 9:08 am

Unfortunately I can’t publish the exact CSS file because of an NDA, but hopefully later today I will publish a ‘sanitised’ version of it. (Basically, ensuring that there aren’t any comments in there that shouldn’t be in there.) :)

2009-09-02 – 9:09 am

It’s the consistent ordering of the properties that results in better compression, rather than their alphabetical ordering. It just happens that ordering alphabetically is a) easier to implement, and b) semantically simpler (for me at least).

2009-09-02 – 9:10 am

You’re right, Peter, there are further ordering optimisations that can be made. I will definitely investigate implementing a more ‘intelligent’ ordering of the properties based on their frequency within the file.

2009-09-02 – 1:48 pm

Barry, Ordering based on the frequency in the file may be better but it won’t lead to an optimal ordering either. An optimization algorithm (e.g. something like simulated annealing or genetic algorithms) with the gzip size as the cost function will (probabilistically.)

2009-09-02 – 3:10 pm

you should check out this CSS compressor
http://www.andy-roberts.net/software/csscompressor/index.html

2009-09-03 – 10:23 pm

@Barry in one of your comments you noted “my code actually parses the string replacement while YUI has a string replacement system.”

Could you elaborate more on this? Did you actually build a java based CSS parser, or are you using regular expressions to do the replacements and minifying?

Thanks.

2009-09-04 – 9:10 am

@John: In a way, yes. Basically, I have a bunch of classes that represent the various ‘bits’ that make up a CSS file: Selectors, Properties, and what I’m calling “Parts” (comma separated values for properties). So the way my system works is that it basically parses the CSS file into a bunch of these classes — selectors have properties, and properties have parts. This means that, unlike YUI, I’m not looking at the ENTIRE file when I’m minifying — rather, I’m dealing with it on a much smaller scale. Regular expressions are still used within the parts themselves, and I also do some basic pre-formatting before I actually parse the file, like removing comments and tabs, newlines and carriage returns.

2009-09-05 – 6:34 pm

zero value give error
p{ padding:0}

2009-09-09 – 4:37 pm

Web Optimizer ( http://code.google.com/p/web-optimizator/ ) incorporates several ways of CSS/JS minimization and use CSS rule hash to complete CSS Sprites / data:URI transformation. Can CSS Minifier return any kind of array of computed CSS rules? It will great to apply it to Web Optimizer logic.

Web Optimizer automates all possible clientside optimization actions for PHP websites.

Add your voice