7/1/2006 - Partial Retraction: Ok, so after testing this on IIS (I was using Cassini when I learned about it) its a little less cool than I originally thought. You still need to add the file extension to the list in IIS so it knows which program is handling requests for the given file type. That's a little less cool. Stinky for sites where you only have FTP access and not direct control of IIS. The concept worked with Cassini because its all about .Net, all files seem to go up through the .Net handler. It looked a little funny running trace.axd and seeing requests for image files register in the trace utility. I guess that should have been my first clue.
I unearthed a real gem today. Our web standards movement has made our CSS files much more sophisticated. We're reaping the benefits of simple XHTML markup, flexible designs and everything else the web standards movement is enamored about.
There's always been this nagging problem of relative paths to image files in the CSS, javascript files or anything else that isn't really executed on the server before its rendered to the browser. The problem comes in when a web site is developed locally, which means it has an application name in its path. When the site is migrated to the staging or production server, the application name is gone. The following URLs point to the same file, depending on which environment you're working in:
Local Development Environment:
"http://localhost:1978/web/images/gobbler.png"
Staging or Production Environment:
"http://www.company.com/images/gobbler.png"
These can be referred to as "absolute" paths. Note, everthing before the forward slash in front of "images" will depend on the environment.
So here in lies the rub:
The CSS file(s) will often contain references to background images. They can reference the images using a relative path. Relative paths use the double period ("..") syntax to reference the parent folder and thus identify the path "relative" to the current location:
"../../images/gobbler.png"
That can be referred to as a "relative" path.
The problem comes in when two web pages use the same CSS file(s) and they're in different folders. Suppose one page is in the root folder of the web site and the other page is three folders down from the root. They would have to use different "relative" paths to reach the same file, right?
ASP.Net 2.0 to the rescue!
Now, we could always just write an .aspx file that contains the normal CSS content and embed server side code that conditionally renders the application name before all file references to make them "absolute" paths.
The issue with this approach is that your web page uses the <link> tag to reference the .aspx page like this:
<link rel="stylesheet" type="text/css" href="/css/print.aspx" />
I've been told that some browsers won't treat this reference exactly the same as one with a .css extension, so they always download the file instead of caching it. I don't know this to be exactly true, but this gem I describe below solves that problem, so everyone is happy.
Here's how ASP.Net 2.0 can be configured to use server side code inside .css files and dynamically insert the application name:
- Open web.config in a text editor
- Add an entry to <buildProviders> that tells ASP.Net which build provider to use:
<system.web>
<compilation debug="false">
<buildProviders>
<add type="System.Web.Compilation.PageBuildProvider" extension=".css" />
</buildProviders>
</compilation>
</system.web>
- Add an entry to <httpHandlers> that tells ASP.Net which factory to use:
<httpHandlers>
<add type="System.Web.UI.PageHandlerFactory" validate="true" path="*.css" verb="GET" />
</httpHandlers>
- Open you CSS files in a text editor
- In the first line of each CSS file, set the content type:
<%@ ContentType="text/css" %>
- Add the application path before each file reference in the CSS file
background-image:url<%= Request.ApplicationPath %>/images/gobbler.png");
Now you can easily move from your development environment to your staging environment without fear of breaking your image paths. Files in various levels of the directory structure can use the same reference because everything has a path that begins at the root. No more ".." syntax headaches. I love it!