Resolving CSS imports with CssCombine
Friday, January 1st, 2010When designing websites, I usually write multiple stylesheets for multiple parts of the website. For example, for gljakal.com I had 5 different stylesheets:
- header.css for the header/logo area,
- content.css for the content area,
- sidebar.css for the sidebar,
- footer.css for the footer
- and finally theme.css, that includes the style for all the above:
@import url("header.css"); @import url("sidebars.css"); @import url("content.css"); @import url("footer.css");
On more complex projects, I usually have even more stylesheets. One thing I am usually constant about however is having a generic theme.css or style.css that includes the other files. This is convenient because in my HTML pages I just have to link only one stylesheet file.
This technique works really well when testing the website on my local machine, however in production it has the downside of generating multiple requests on the client.
To address this problem, I wrote a small command-line program that would follow @import
instructions and merge the imported files in the main one. It’s called CssCombine.
The code (in c#) is merely 48 lines long:
using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; namespace CssCombine { class Program { static void Combine(string parFileName, StringBuilder parOutput) { string[] lines = System.IO.File.ReadAllLines(parFileName); foreach (string s in lines) { if (s.Trim() != "") { Regex rgx = new Regex(@"@import\s+url\s*\((.*)\);", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); string[] sx = rgx.Split(s); if (sx.Length > 1) { string sFile = sx[1].Replace("\"", "").Replace("'", ""); sFile = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(parFileName), sFile); Combine(sFile, parOutput); } else { parOutput.AppendLine(s.Trim()); } } } } static void Main(string[] args) { if (args.Length != 2) { Console.WriteLine("Usage: CssCombine [input.css] [output.css]"); } else { string input = args[0]; string output = args[1]; StringBuilder sbOutput = new StringBuilder(); Combine(input, sbOutput); System.IO.File.WriteAllText(output, sbOutput.ToString()); } } } }
Or you can download the compiled program here.
Another optimization would be to minify the resulting file. I use Yahoo’s YUI Compressor for that.