CSS: CSS Browser Selector
Each browser has its quirks. Having a clear way of organizing the work arounds
for those quirks is a challenge. Using CSS selectors is not a new idea, but I thought it might be helpful to others to give an example of the technique and how we've been able to successfully deploy it for revolutionhealth.com.
First, for IE (the browser that usually requires a hack), we can rely on conditional comments. This is good because it means we don't need to depend on Javascript. For other browsers we'll have to rely on a document.write solution. For Safari, Opera, and Firefox, we rely on the script from http://rafael.adm.br/css_browser_selector/ and for IE, conditional comments.
Here's what we include at the top of our document. (The browser_detect_start partial.)
<!--[if lt IE 7.]>
<div class='ie ie6'>
<![endif]-->
<!--[if IE 7]>
<div class='ie ie7'>
<![endif]-->
<script type="text/javascript">//<![CDATA[
var d = browserCSSDetection();
if( d.browser != "ie" ){ document.write( "<div class='" + d.browser + " " + d.os + "'>" ); }
//]]></script>
And here's what we do for the end of the document. (The browser_detect_end partial.)
<!--[if IE ]>
</div>
<![endif]-->
<script type="text/javascript">//<![CDATA[
var d = browserCSSDetection();
if( d.browser != "ie" ){ document.write( "</div>" ); }
//]]></script>
The browser detection in Javascript. This could be enhanced further, but for us this allowed us to get the site working relatively easy in Konqueror. As well it enabled us to fix our menu's so that they float over flash in Linux using this techinque.
function browserCSSDetection()
{
// see: http://rafael.adm.br/css_browser_selector/
var ua = navigator.userAgent.toLowerCase();
var is = function(t){ return ua.indexOf(t) != -1; };
var b = (!(/opera|webtv/i.test(ua))&&/msie (\d)/.test(ua)) ?
('ie ie'+RegExp.$1) :
is('gecko/') ? 'gecko' :
is('opera/9') ? 'opera opera9' :
/opera (\d)/.test(ua) ? 'opera opera'+RegExp.$1 :
is('konqueror')?'konqueror' :
is('applewebkit/') ? 'webkit safari':
is('mozilla/')?'gecko':'';
// see: http://www.mozilla.org/docs/web-developer/sniffer/browser_type.html
var os = (is('x11')||is('linux'))?' linux':is('mac')?' mac':is('win')?' win':'';
var css = {browser:b,os:os};
return css;
}
Finally, to make all this fit nicely into a layout:
<head>
<%= javascript_include_tag 'browser_detect' %>
</head>
<body>
<%= render :partial => "browser_detect_start" %>
<%= @content_for_layout %>
<%= render :partial => "browser_detect_end" %>
</body>
Update:
Here's a simple example of what this enables. The advantage of this over a conditionally included file is it keeps everything about the login box isolated to one place. You don't need to worry about openning up a separate file to make your IE fixes. We do use iefix specific CSS for our site, but only for very large features like menus
#login {
padding:0px;
}
.ie6 #login {
padding: 2px;
}