Really Simple Browser Detection with jQuery
For my Serious redesign, I push the envelope in terms of CSS’ advanced selector functionality. Stuff like:
p:first-child
p:first-child:first-letter
p:first-child:after
p:first-child:first-line
Plus lots of other stylistic tricks that require CSS3 support in order to display as intended. Fortunately, most of the browsers to which I am catering with this new design have no problems with most of the advanced stuff. Of course, Internet Explorer chokes on just about everything, but fortunately IE’s proprietary conditional comments make it easy to fix things up with some “special” styles:
<!--[if IE 6]>
<link rel="stylesheet" type="text/css" media="Screen" href="https://perishablepress.com/press/wp-content/themes/serious/css/ie6.css" />
<![endif]-->
<!--[if IE 7]>
<link rel="stylesheet" type="text/css" media="Screen" href="https://perishablepress.com/press/wp-content/themes/serious/css/ie7.css" />
<![endif]-->
<!--[if IE 8]>
<link rel="stylesheet" type="text/css" media="Screen" href="https://perishablepress.com/press/wp-content/themes/serious/css/ie8.css" />
<![endif]-->
Bam, just like that. In each of these stylesheets, I essentially “undo” all of the cool CSS effects that modern browsers get, including some crafty <pre>
treatments that you are hopefully enjoying ;) Notice that we can specify an additional/alternate stylesheet for any version of IE. For the Serious theme, I provide around 20 remedial rules for IE 6, 7, and 8. Once IE 9 is released, we’ll need four additional stylesheets. Moving on..
So that takes care of Microsoft, but there are still other browsers to consider. I designed the new Serious theme to look perfect in the latest version of Firefox (3.5), which uses a different rendering engine than Safari, Opera, and Chrome. Fortunately, I didn’t need to change much for older versions of Firefox, but some of the other modern browsers required a few tweaks to get things looking just right. To do this, I could have used a bunch of ugly CSS hacks, but there are too many risks and “gotchas” when it comes to differentiating between Safari and Opera, for example. So I decided to keep things as simple and specific as possible. Here’s how I did it..
Really Simple Browser Detection for Modern Browsers
Before getting into it, let me just acknowledge that browser detection should only be used as a last resort. If you can design a site without needing any hacks or alternate presentational trickery, then good for you, no browser detection needed. When it comes to pushing the envelope and trying new things, however, you’ll almost always find presentational discrepancies in modern browsers. In any case, it turns out that I do feel as if browser detection was the ideal solution for the new design, mostly due to the fact that the modifications were few and fairly cosmetic in nature, so no big deal if JavaScript is not available to the user.
Basically, I want to apply an additional stylesheet to each of the modern browsers. To do this with IE, conditional comments work perfectly. I almost wish that every browser included some sort of conditional-comment functionality. It would make all this browser-detection stuff unnecessary. In any case, here is a list of browsers that I want to target with CSS (in no particular order):
- Camino
- Chrome
- Opera
- Safari
For these four browsers, I created four unique stylesheets and then conditionally link to them with a few snippets of jQuery:
<div class="altcss">
<script type="text/javascript">$.browser.camino = /camino/.test(navigator.userAgent.toLowerCase()); if ($.browser.camino) {
document.write('<link rel="stylesheet" href="http://domain.tld/css/camino.css" type="text/css" media="screen">'); }</script>
<script type="text/javascript">$.browser.chrome = /chrome/.test(navigator.userAgent.toLowerCase()); if ($.browser.chrome) {
document.write('<link rel="stylesheet" href="http://domain.tld/css/chrome.css" type="text/css" media="screen">'); }</script>
<script type="text/javascript">$.browser.opera = /opera/.test(navigator.userAgent.toLowerCase()); if ($.browser.opera) {
document.write('<link rel="stylesheet" href="http://domain.tld/css/opera.css" type="text/css" media="screen">'); }</script>
<script type="text/javascript">$.browser.safari = /safari/.test(navigator.userAgent.toLowerCase()); if ($.browser.safari) {
document.write('<link rel="stylesheet" href="http://domain.tld/css/safari.css" type="text/css" media="screen">'); }</script>
</div>
Basically, each of these snippets tests the client’s user-agent string and writes a <link>
to any matching stylesheet. Of course JavaScript is required on the user’s browser, so it’s best not to use this technique for anything beyond minor cosmetic enhancements.
As for the code itself, I am know there are more elaborate ways of sniffing and detecting browsers, but I wanted to keep things as simple as possible. Also, this code could also be simplified to exist within a single <script>
element:
<div class="altcss">
<script type="text/javascript">
$.browser.camino = /camino/.test(navigator.userAgent.toLowerCase()); if ($.browser.camino) {
document.write('<link rel="stylesheet" href="http://domain.tld/css/camino.css" type="text/css" media="screen">'); }
$.browser.chrome = /chrome/.test(navigator.userAgent.toLowerCase()); if ($.browser.chrome) {
document.write('<link rel="stylesheet" href="http://domain.tld/css/chrome.css" type="text/css" media="screen">'); }
$.browser.opera = /opera/.test(navigator.userAgent.toLowerCase()); if ($.browser.opera) {
document.write('<link rel="stylesheet" href="http://domain.tld/css/opera.css" type="text/css" media="screen">'); }
$.browser.safari = /safari/.test(navigator.userAgent.toLowerCase()); if ($.browser.safari) {
document.write('<link rel="stylesheet" href="http://domain.tld/css/safari.css" type="text/css" media="screen">'); }
</script>
</div>
And of course, you aren’t limited to the browsers specified here. You could easily target another by emulating the pattern according to the user-agent or name of the additional browser. For example, we could add a custom stylesheet for the Flock browser like so:
<script type="text/javascript">$.browser.flock = /flock/.test(navigator.userAgent.toLowerCase()); if ($.browser.flock) {
document.write('<link rel="stylesheet" href="http://domain.tld/css/flock.css" type="text/css" media="screen">'); }</script>
Finally, because this is JavaScript, I place this block of code at the end of my XHTML document, just before the closing <body>
element. It could just as easily be argued that this code should be placed in the document <head>
because it’s ultimately referring to CSS, but I will leave it up to you to decide for yourself.
Update: in the comments, Gustavo informs us that, as of jQuery 1.4, the $.browser
variable is replaced by $.support
. So if you’re using jQuery 1.4 or better, you’ll need adjust the code accordingly. Here is an example showing how this would look for the Flock browser:
<script type="text/javascript">$.support.flock = /flock/.test(navigator.userAgent.toLowerCase()); if ($.support.flock) {
document.write('<link rel="stylesheet" href="http://domain.tld/css/flock.css" type="text/css" media="screen">'); }</script>
26 responses to “Really Simple Browser Detection with jQuery”
Hi Jeff,
what I dont understand is: Why you wrap the jquery-code in that “
altcss
” class?Hi Don, good question! I use that in my designs to hide the contents and prevent them from breaking the layout. You can read more about it here.
Very useful, love this! : )
Hi Jeff,
in jQuery 1.4
$browser
is still supported but deprecated. The$support
does not replace the$browser
as you suggested above, rather it checks for the standards a browser supports.I assume the reasoning behind that is to elaborate on object detection:
http://www.quirksmode.org/js/support.html
$browser
is still good in 1.4 but not recommendedhttp://api.jquery.com/jQuery.browser/
$support
does not check for particular browsers but rather for what a certain browser supports – be it html5 CSS3 etc.http://api.jquery.com/jQuery.support/
Thanks still for the nice insights …
Hi tb,
Thanks for the information. Is there a better way to go about it using jQuery?
Hey Jeff, I have not quite understood the support tag itself, but it seems that one can actually add to it as you are actually doing it … currently i am trying to figure out how to provide fallback for html5 funtionality as such. Your code is actually correct I think, I just could not find the var flock at the jQuery $support page my mistake … Still I might write a plugin checking only for html5 tags as such … thanks again for the pointers in the right direction
cheers
RE:
$browser
is still good in 1.4 but not recommendedActually, the whole “feature detection” over “browser detection” thing is 100% true when it comes to coding in javascript.
Here’s a bit more “toned down” version of the same information:
http://docs.jquery.com/Release:jQuery_1.3#No_More_Browser_Sniffing
When (as here) using javascript to serve different stylesheets (or IMO better idea to put browser-identifying classes on body or html), then browser detection is fine *if properly used*.
Which means (as here) for progressive enhancement, non-essentials like design-y show-off stuff, not relying on javascript for basic content/navigation functionality.
Of course, people who aren’t 100% sure they know what they’re doing, or looking to just get bulletproof sites coded to deadlines should just use bog-standard HTML/CSS and not worry about all the bleeding-edge stuff. Cause doing fancy stuff like this will blow out a project’s time budget geometrically, and few clients will pay for the pixel-perfection tweaking time. Staying up all night on your own site, well if that’s your idea of fun go for it! 8-)
Hi there!
Is there a way to detect the OS and the Browser with jQuery without using deprecated code?
This has to be one of the best browser detectors I have used:
http://rafael.adm.br/css_browser_selector/
It writes several classes into the [html] tag, which you can then use to target browsers and platforms (I bet you can guess which browser needs the most “help”).
Best of all, your CSS will validate.
Your place is valueble for me. Thanks!…
I am a bit confused after reading all of this. Should I use the script with the $.browser or not? It worked fine.
My problem is a bit unique. Usually, I have no issues between browsers. My CSS is clean, and works in Safari, Chrome, IE, and Firefox.
However, with this latest site, I am using a jquery plugin for rounded corners. It adds approximately 5-10 px to the top and bottom of the box I chose to round the corners on. This is no problem in 3 of 4 browsers, but for some reason, in Safari, it is adding to the left and right as well.
Now, in Safari, the 2 columns (both with rounded corners) are merging together, due to the added width. If I change the CSS width of the left column from 27% to 24%, I get the same look as the other 3 browsers.
If anyone has any ideas, let me know. For now I have used the script, provided in this post, to detect the browser, and use the 24% width for safari only.
I am baffled, because I have never had this problem, however have used the rounded corners plugin on one other site, and just checked it in Safari, it has added width to both columns as well, but there is still a slight gap, so am not worried about that.
Sorry for the long email – I hope someone can help me fix this with NO HACKS / browser detection / changing stylesheets, but in the meantime, thank you for this Safari Only fix.
Detecting browser name and version
$(document).ready(function()
{
if ( $.browser.msie ){
if($.browser.version == '6.0')
{ $('html').addClass('ie6');
}
else if($.browser.version == '7.0')
{ $('html').addClass('ie7');
}
else if($.browser.version == '8.0')
{ $('html').addClass('ie8');
}
else if($.browser.version == '9.0')
{ $('html').addClass('ie9');
}
}
else if ( $.browser.webkit )
{ $('html').addClass('webkit');
}
else if ( $.browser.mozilla )
{ $('html').addClass('mozilla');
}
else if ( $.browser.opera )
{ $('html').addClass('opera');
}
});
this jquery detecting which browser you are using and adding in html tag so u can use with this class
eg: if using ie6
.ie6 .className
{ property: value;
}