Browser sniffing is bad. But sometimes unavoidable. But doing it on the server is bad, because UA string is unreliable. The solution is to use conditional comments and let IE do the work. Because you're targeting IE most of the times anyway.
In fact IE8 is a decent browser for the most practical purposes and often you're just targeting IE before 8.
Conditional comments in practice use the following pattern:
- Load the decent browsers CSS
- Conditionally load IE6,7 overrides
The drawback is that IE6,7 get two HTTP requests. That's not good. Another drawback is that having a separate IE-overrides stylesheet is an excuse to get lazy and instead of solving a problem in a creative way, you (and the team) will just keep adding to it.
We can avoid the extra HTTP request by creating our CSS bundles on the server side and having two browser-specific but complete stylesheet files:
- The decent browsers CSS
- The complete CSS for IE6,7 not only the overrides
Then the question is loading one of the two conditionally without server-side UA sniffing. The trick (courtesy of duris.ru) is to use conditional comments to comment out the decent CSS so it's not loaded at all:
<!--[if lte IE 7]> <link href="IE67.css" rel="stylesheet" type="text/css" /> <![endif]--> <!--[if gt IE 7]><!--> <link href="decent-browsers.css" rel="stylesheet" type="text/css" /> <!--<![endif]-->
The highlighting suggests what the decent browsers see.
IE6,7 see something like this after the conditional comments are processed:
<link href="IE67.css" rel="stylesheet" type="text/css" /> <!-- <link href="decent-browsers.css" rel="stylesheet" type="text/css" /> -->