The Problem
I've been working on refactoring a project from tables to a table-less design with CSS. The stated benefit (with which I agree wholeheartedly) is that using tables for layout of non-tabular data (that is, using tables to position blocks of text) is improper because it is using the wrong tool for the job. Any artisan (woodworker, metalsmith, sculptor) would tell you this is a huge no-no, but in web design, it's gone unchallenged for virtual centuries (i.e. a few years). But the "it's-just-bad-art-and-bad-zen" argument isn't the whole story: alternative browsers (cell phones, audiobrowsers for the deaf, etc) have no idea what these tables mean, and will therefore confuse their users. The problem is that though CSS is standardized, some broswers (most notoriously, IE) don't conform to the standard.
The Established Solution
So far, people have been adding hacks to their CSS to get around browser differences. Things like the star html hack and the mac backslash hack are ingenious, but they impede development. They're hard for future programmers to understand (even with liberal comments), and they're logically messy. (No self-respecting C++ programmer would write
It's just ugly.)
width = 100;
callBackSetWidth(120); //Linux platforms before
//1997 don't support this,
//so they get the value 100
My Solution
I came upon my solution by accident. I have been using the .jsp extension for my CSS files for a while now for the sole purpose of being able to use the <c:url> tag. If I use an image for a background, I don't want the link to have to reference my project name - epecially since the context may change to root at deployment.
Because the CSS files were already dynamically generated, I thought of doing browser dependency with
<c:set var="user_agent" value="${headerValues['user-agent'][0]}" />
<c:choose>
<c:when test="${fn:startsWith(user_agent, 'Mozilla/5.0')}">
<%-- Firefox 1.0, Gecko, etc --%>
<c:set var="firefox" value="${true}" />
<c:set var="ie" value="${false}" />
<c:set var="app_width" value="760" />
</c:when>
<c:otherwise>
<%-- IE 6 --%>
<c:set var="firefox" value="${false}" />
<c:set var="ie" value="${true}" />
<c:set var="app_width" value="762" />
</c:otherwise>
</c:choose>
at the top of the file. You could easily have more cases if you need to support more browsers. Notice first the "ie" and "firefox" variables. These can be used by final in the page scope, though) while allowing differences between browsers.