Hack-less CSS with ColdFusion

We have finally made the big leap at work: our online store will no longer be supporting ancient web browser versions. We’ve done the analysis of our traffic logs, and it is nowhere near economically viable to support the two Mac IE users, or the one Win98/IE5 user that we have. Maybe if they bought thousands of dollars worth of product … but even then it would be hard to justify.

However, we aren’t complete bastards. The version 6 (FF1.0) browsers are all still supported, inasmuch as we have been able to test them. There’s still no Flash or Java or ActiveX, and the JavaScript is as vanilla and browser-agnostic as we can make it. It’s not like we’re trying to drive our customers away, it’s just that there are too few hours in the day to spend hunting for browser bugs for that extra $15 sale. Not gonna happen.

That all being said, there are of course plenty of bugs between even the supported browsers, most related to CSS positioning. In order to keep my sanity, I am not using any CSS hacks[1] to fix these bugs. How is that, you ask?

First, let me say that this was not my idea. I saw it in an RSS feed a few months ago, but for the life of me cannot remember which one. If someone recognizes the technique and would like to point out the originator, I’d be happy to provide the appropriate linkage and citation.

I have a browser.cfc with a function cssClasses that looks like this:

<cfset var ret=LCase(this.AppName)>
<cfif IsNumeric(this.AppVersion)>
	<cfset ret=ListAppend(ret,LCase(this.AppName) & Int(this.AppVersion))>
	<cfset ret=ListAppend(ret,LCase(this.AppName) & Int(this.AppVersion*10))>
</cfif>
<cfif this.isMac()><cfset ret=ListAppend(ret,"mac")></cfif>
<cfif this.isWin()><cfset ret=ListAppend(ret,"win")></cfif>
<cfreturn ListChangeDelims(ret," ")>

When called, I get results like this:

Browser cssClasses()
MSIE 6.0 (Win)msie msie6 msie60 win
MSIE 5.0 (Mac)msie msie5 msie50 mac
Navigator 4.8 (Win)mozilla mozilla4 mozilla48 win
Opera 7.54 (Win)opera opera7 opera75 win
Firefox 1.5.0.4 (Win)firefox firefox1 firefox15 win

And so on.

In my header template(s), I have added class="#Request.Browser.cssClasses()#" to the body tag. This gives the body of the page classes that identify the browser, version, and OS that the client is running. Instead of ugly CSS hacks, then, I can do this:

/* Fix some positioning strangeness with Opera v7.x */
#Logo { margin-top: 21px; height: 133px; }
body.opera7 #Logo { margin-top: 0px; background-position: 0px 21px; height: 154px; }
/* MSIE doesn't support min-height, but ...
   we don't want to apply a height to everyone that does */
#Content { min-height: 250px; }
body.msie #Content { height: 250px; }
/* Try to use a 24-bit PNG with alpha channel,
   fall back to a GIF for IE<7,
   but then re-upgrade for IE7 */
#CartMiddle { background: url(images/cart-back.png) top left repeat-y; }
body.msie #CartMiddle { background-image: url(images/cart-back.gif); }
body.msie7 #CartMiddle { background-image: url(images/cart-back.png); }

Benefits:

  • Profoundly easier to read than trying to remember which hacks work with which browser.
  • No hack-entanglement issues.
  • Versionable. (Hence why I include browser-no-version, browser-major-version, and browser-major-minor-version classes.)

Drawbacks:

  • If the client has set their User-Agent to something non-standard, then they are going to get undefined results. But then, why shouldn’t they?
  • Some really ancient browsers don’t support multiple classes per tag. You’ll need to do some additional work to sniff them out beforehand.

  1. Okay, I’m using one: the be-nice-to-Mac-IE5 hack, to fix the fact that it doesn’t like @media rules.

Published by

Rick Osborne

I am a web geek who has been doing this sort of thing entirely too long. I rant, I muse, I whine. That is, I am not at all atypical for my breed.