Minimizing CSS Files with Ruby
Monday, January 18 2010
I've been using YSlow a good deal lately to attempt to wring out every last ounce of speed from Department of Numbers. I'm not sure if this is the best investment of my time or not, but it is a strangely satisfying task. I've heard that Google may be considering factoring page speed into their ranking algorithms, so I guess that's how I justify expending the effort to try to win these infinitesimal performance gains.
So as YSlow recommends, I decided I'd consolidate and compress DoN's css files to both limit the number of HTTP requests and return the smallest file possible. I grabbed the Ruby css compressor Rainpress and ran my css files through it. While I did get a noticeably smaller file this way it also became quite difficult to read. As I still value the whole view source nature of the web, I don't want to unnecessarily obfuscate my html and css for a negligible performance boost (negligible in my case at least). Given that Rainpress appears to have file input and output options but no formatting options, I decided to try to make something really simple (dumb some would say) where I could customize the output a bit more.
Here's what I came up with: mincss.zip
#!/usr/bin/env ruby
#define formatting around the characters
colon = ':'
semicolon = '; '
comma = ','
open_brace = ' {'
close_brace = '}'
file = !STDIN.tty? ? STDIN.read : File.read(ARGV[0])
file.split('}').each do |block|
#one block per line
block.gsub!(/\n/,' ')
#get rid of comments
block.gsub!(/\/\*.*?\*\//m,'')
#apply formatting defined above
block.gsub!(/\s*:\s*/,colon)
block.gsub!(/\s*;\s*/,semicolon)
block.gsub!(/\s*,\s*/,comma)
block.gsub!(/\s*\{\s*/,open_brace)
#single spacing
block.gsub!(/\s\s+/,' ')
puts block.strip + close_brace if block.include?('{')
end
To maintain css readability I opted for one block per line with spacing after the semicolons and before the open braces. I think the results are more appealing now, but I can change this very easily if I wanted to by manipulating the define formatting around the characters section in the code above. Just modify the strings to represent what you want the space around each of those characters to look like.
As I said, this is pretty dumb code. It doesn't have any knowledge of css syntax or grammar it can use to shorten or correct your code; it just removes extra spacing and consolidates your css to one block per line. If you really want to get your css file as small as possible, Rainpress is probably the best bet as far as Ruby utilities go. But if you're looking for a flexible and concise yet readable view of your css, you might find this tool useful.
Usage is as follows:
> mincss.rb styles.css
> cat styles.css | mincss.rb
You can pass the input css via STDIN or as an argument. I operate with 3 distinct css files in my development environment but then have a Rake task that concatenates them and pipes the output to mincss.rb for the production environment. Now my development css files are verbose and my production css is concise.
Update: A reader sent in a fix for a greedy inner-block comment deletion. All the code has been updated. Thanks Jeff!
