Reduce the weight of stylesheets by 35% at runtime

by Mads Kristensen 21. August 2006 05:23

It is always desirable to produce the smallest amount of client-code at any given time. That includes HTML, JavaScript and CSS files. The more client-code you produce, the longer it takes to download and render the web page. Let’s see how easy it is to reduce CSS files by 35 % at runtime, but first we have to set some rules for the feature.

  1. No changes to the original .css files must be made
  2. Must work on all .css files without exception
  3. No negative performance impact
  4. Use both the client's and the server's cache
  5. Update the cache when the .css files change 
  6. Simplest possible implementation

We are going to use a generic handler (.ashx) to reduce the .css files and serve them to the browser. The handler has to do 2 things. It must reduce the files and add them to the browsers cache. The method that reduces the file, removes all unnecessary whitespace and comments. The more whitespace and comments you use, the more it will reduce the file.

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

 

using System;

using System.Web;

using System.IO;

using System.Text.RegularExpressions;

using System.Web.Caching;

 

public class css : IHttpHandler

{

 

  public void ProcessRequest(HttpContext context)

  {

    string file = context.Server.MapPath(context.Request.QueryString["path"]);   

    ReduceCSS(file, context);

    SetHeaders(file, context);

  }

 

  /// <summary>

  /// Removes all unwanted text from the CSS file,

  /// including comments and whitespace.

  /// </summary>

private void ReduceCSS(string file, HttpContext context)

{

  FileInfo fi = new FileInfo(file);

  // Make sure that it only accesses .css files

  if (!fi.Extension.Equals(".css", StringComparison.OrdinalIgnoreCase))

  {

    throw new System.Security.SecurityException("No access");

  }

 

  string body = fi.OpenText().ReadToEnd();

 

  body = body.Replace("  ", String.Empty);

  body = body.Replace(Environment.NewLine, String.Empty);

  body = body.Replace("\t", string.Empty);

  body = body.Replace(" {", "{");

  body = body.Replace(" :", ":");

  body = body.Replace(": ", ":");

  body = body.Replace(", ", ",");

  body = body.Replace("; ", ";");

  body = body.Replace(";}", "}");

  body = Regex.Replace(body, @"/\*[^\*]*\*+([^/\*]*\*+)*/", "$1");

  body = Regex.Replace(body, @"(?<=[>])\s{2,}(?=[<])|(?<=[>])\s{2,}(?=&nbsp;)|(?<=&ndsp;)\s{2,}(?=[<])", String.Empty);

 

  context.Response.Write(body);

}

>

>

>

 

  /// <summary>

  /// This will make the browser and server keep the output

  /// in its cache to eliminate negative performance impact.

  /// </summary>

  private void SetHeaders(string file, HttpContext context)

  {

    context.Response.ContentType = "text/css";  

    // Server-side caching

    context.Response.AddFileDependency(file);

    context.Response.Cache.VaryByParams["path"] = true;

    // Client-side caching

    context.Response.Cache.SetETagFromFileDependencies();

    context.Response.Cache.SetLastModifiedFromFileDependencies();

  }

>

>

>

 

  public bool IsReusable

  {

    get

    {

      return false;

    }

  }

 

}

Implementation

Download the css.ashx file below and add it to the root of your website. Then change the path to the stylesheet in the header of the web page to point to the css.ashx with the original .css file name as parameter:

<link rel="stylesheet" type="text/css" href="css.ashx?path=common.css" />

<link rel="stylesheet" type="text/css" href="css.ashx?path=folder/menu.css" />

Download

css.zip (0,82 KB)

* Only $4.95/month ASP.NET & Windows 2008 + IIS 7 Hosting! FREE SQL Included

Tags:

ASP.NET

Comments

8/22/2006 5:11:01 PM #

 Damien Guard

This looks to me like a massive security problem.

What is to stop a hacker looking at the source and typing http://www.yoursite.com/css.ashx?path=default.aspx and grabbing the source to the aspx?

Or indeed http://www.yoursite.com/css.ashx?path=web.config to grab all your connection string details including passwords?

You'd be much better off writing a HTTP handler that matched a pattern of ".css" and picked it up there.

Also bear in mind that content is normally compressed over a HTTP stream with either deflate or gzip so the savings won't be as high as you imagine.

[)amien

Damien Guard |

8/22/2006 6:41:52 PM #

 Mads Kristensen

Damian, thanks for pointing it out - you are absolutely right. The easy solution would be to check for the .css file extension and make sure to only serve those files. The solution you suggested is the right one if you have access to the IIS, otherwise you have to use this example.

Mads Kristensen |

8/23/2006 5:52:00 AM #

Mads Kristensen

I have made a change that makes sure that it only will serve .css files.
-Mads

Mads Kristensen |

12/8/2007 3:52:43 AM #

taras

Mads, is there any chance to hook this handler to stylesheets contained within a theme (~/App_Theme/../*css) ?

taras Ukraine |

4/24/2008 4:40:15 AM #

pingback

Pingback from pimp.webdevelopernews.com

Removing Whitespace From Your Pages With ASP.NET

pimp.webdevelopernews.com |

6/4/2008 4:36:19 AM #

Peter Smith

Just curious...why wouldn't you do this at compile time instead? Stick it into your MSBuild script, for instance?

Peter Smith United States |

8/18/2008 10:55:39 PM #

jalal

i couldn,t use this article please give me a sample and help me

jalal Iran |

9/25/2008 5:11:49 AM #

trackback

Using Cache And Compression For Performance

Using Cache And Compression For Performance

Tim-Stanley.com |

12/3/2008 12:19:15 PM #

baldwin

that is great but the images in CSS look not work well due to the path problem.

baldwin |

8/12/2010 12:12:51 AM #

pingback

Pingback from aio4s.com

Remove whitespace from your ASP.NET page |  All in one for social – Blog

aio4s.com |

Comments are closed

About the slave

Mads Kristensen Mads Kristensen
Web developer at ZYB and founder of BlogEngine.NET. More...

LinkedIn ZYB Facebook Last.fm Twitter View Mads Kristensen's profile on Technorati

The Lounge

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2008