CSS minifier and alphabetiser

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

There are quite a few CSS minifiers out there, which can bring the raw size of your CSS files down substantially. There are, however, significant gains to be made if the CSS is minified so that it gzips better. 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 gzipped file will be stored most efficiently when there are many recurring strings in the file. This means that when writing CSS files, this code:
[sourcecode language=”css”].pony {
border: solid red 1px;
font-weight: bold;
}
.lemur {
border: solid red 1px;
font-weight: normal;
}[/sourcecode]
will be better-compressed than this:
[sourcecode language=”css”].pony {
border: solid red 1px;
font-weight: bold;
}
.lemur {
font-weight: normal;
border: red solid 1px;
}[/sourcecode]
In the first sample, notice that we have a very long string that occurs twice:

 {
border-style: solid red 1px;
font-weight: 

In the second sample, there are strings that occur more than once, but they’re much shorter. The gzip algorithm can, in the first case, replace that entire long string with a much shorter placeholder.

What it does

So, how can we optimise CSS for gzipping, then? A file that’s minified using this CSS Minifier will have these operations applied:

  • All comments removed.
  • The properties within all selectors ordered alphabetically.
  • The values for all properties ordered alphabetically.
  • All unnecessary whitespace removed.
  • Font weights replaced by their numeric counterparts (which are shorter).
  • Quotes stripped wherever possible.
  • As much text as possible transformed to lowercase.
  • Prefixed properties (for example, -moz-box-sizing) placed before the unprefixed variant (box-sizing).
  • Colours simplified from rgb() to six- or three-digit hex values, or simple names.
  • Units on values of 0 stripped.
  • Multi-parameter items simplified to as few parameters as possible.
  • Various other small tweaks and adjustments made.

By way of example, the following CSS snippet:
[sourcecode language=”css”]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;
}[/sourcecode]
would be formatted to the following (note that line breaks have been added for legibility — no line breaks appear in the final output):

body{background-color:blue;color:#fff;font-family:"trebuchet ms",sans-serif;
margin:0;padding:8px}h1{color:#0f0;font-size:200%;font-weight:700;margin:0;
padding:0}p{line-height:2em;margin:0 0 2em}

Compression results

These are the results of compressing the main CSS file for one of the webapps I develop at work.

 Original size (bytes)Gzipped size (bytes)
Plain8193812291
YUI6443410198
LotteryPost6360910165
CSS Drive6927510795
CSSMin637919896

Download

Head over to GitHub to download the source.

Usage

First, if you haven’t done so yet, compile the code:
[sourcecode]# javac CSSMin.java[/sourcecode]
Then, you can call the minifier by running
[sourcecode]# java CSSMin in.css [out.css][/sourcecode]
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.

You can also raise issues on GitHub, fork the project, commit changes, and more.

If you find this utility useful, let me know!

Comments

25 responses to “CSS minifier and alphabetiser”

  1. Oliver Nassar Avatar
    Oliver Nassar

    Very cool. Never seen this done 🙂

    1. Barry van Oudtshoorn Avatar

      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.

  2. Ray Cromwell Avatar
    Ray Cromwell

    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.

    1. Barry van Oudtshoorn Avatar

      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.

  3. Andrew Sutherland Avatar

    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?

    1. Barry van Oudtshoorn Avatar

      @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.

  4. Robert Schultz Avatar

    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 🙂

    1. Barry van Oudtshoorn Avatar

      @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.

  5. Fabian Avatar

    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?

    1. Barry van Oudtshoorn Avatar

      @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. :/

  6. Aike Avatar
    Aike

    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;
    }

    1. Barry van Oudtshoorn Avatar

      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;
      }

  7. Steve Clay Avatar

    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? 🙂

    1. Barry van Oudtshoorn Avatar

      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.) 🙂

  8. Steve Clay Avatar

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

  9. Thomas J Bradley Avatar

    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?

    1. Barry van Oudtshoorn Avatar

      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).

  10. Peter Michaux Avatar

    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.

    1. Barry van Oudtshoorn Avatar

      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.

  11. Peter Michaux Avatar

    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.)

  12. John Ryding Avatar

    @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.

    1. Barry van Oudtshoorn Avatar

      @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.

  13. Kay.L Avatar

    zero value give error
    p{ padding:0}

  14. sunnybear Avatar

    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.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.