Friday, September 07, 2007

CssCompact: A WebHandler for shrinking CSS files (ASP.NET)

Update (20 Feb 2010): Static regular expression, compiled (performance improvement, but will be negligible for low volume sites). See Compacting CSS on-the-fly for an HttpHandler based on this.

Update (08 July 2009): Check file extension is CSS.

CssCompact is a simple WebHandler for sending smaller CSS files to the client. It simply removes linebreaks, tabs, spaces (before CSS properties) and comments. That way you can still have your commented CSS code, and also save bandwidth.

Use is simple, just pass on the stylesheet as a parameter when loading your stylesheet:

Add to <head>:

<link rel="stylesheet" type="text/css" href="/style/CssCompact.ashx?stylesheet=/style/style.css" />

or

<style type="text/css"> @import "/style/CssCompact.ashx?stylesheet=/style/style.css"; </style>

Create CssCompact.ashx:

<%@ WebHandler Language="C#" Class="CssCompact" %>

using System;
using System.Web;
using System.IO;
using System.Text.RegularExpressions;

public class CssCompact : IHttpHandler
{
 // remove linebreaks, whitespace and comments
 private static RemoveRegex = new Regex(@"^\s+|/\*([^*\\\\]|\*(?!/))+\*/|\r|\n|\t", RegexOptions.Multiline | RegexOptions.Compiled);
 public void ProcessRequest(HttpContext c)
 {
  string stylesheet = c.Request.QueryString["stylesheet"];
  c.Response.ContentType = "text/css";
  if (stylesheet != null)
  {
   string filename = c.Server.MapPath(stylesheet);
   FileInfo f = new FileInfo(filename);
   if(f.Extension == ".css" && f.Exists)
   {
    c.Response.AddHeader("Last-Modified", f.LastWriteTime.ToString("U"));
    c.Response.Expires = 0;
    if(c.Request.HttpMethod != "HEAD")
    {
     using (StreamReader cssStream = f.OpenText())
     {
      string cssContent = cssStream.ReadToEnd();
      cssContent = RemoveRegex.Replace(cssContent, "");
      c.Response.Write(cssContent);
      c.Response.End();
     }
    }
   }
  }
  c.Response.Write("/* No valid style sheet selected */");
  c.Response.End();
 }

 public bool IsReusable
 {
  get
  {
   return false;
  }
 }

}

2 comments:

Stefan Bergfeldt said...

Thanks for a great post. I've improved your code, fixing the security issue, and support multiple stylesheets.
Your code allows the visitor to type in /CssCompact.ashx?stylesheet=/web.config and read the contents of your web.config file.

Karl said...

Great article though I missed a few things in it. I've fixed a few things (compiled the regex, added caching with a file dependency and a querystring to disable it all when debugging). My version can be seen here: http://blog.crazybeavers.se/index.php/archive/compacting-css-on-the-fly/

/ Karl