Plugin Sale! Save 15% on pro plugins with discount code: FALL2020
Web Dev + WordPress + Security

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>

Jeff Starr
About the Author
Jeff Starr = Web Developer. Security Specialist. WordPress Buff.
GA Pro: Add Google Analytics to WordPress like a pro.

26 responses to “Really Simple Browser Detection with jQuery”

  1. Tyler Abell 2009/12/13 1:42 pm

    Sounds great, I am always worried that a user will not have JavaScript enabled, thats why I tend not to depend on JavaScript. Yes, it will look best with JavaScript but I always make sure it looks great without it. I as well tend to stay away from CSS3 depended elements, and other elements such as “border-radius”.

  2. Tyler Abell 2009/12/13 3:54 pm

    That is completely true, especially those visiting your website, one that is of design would hopefully be updated and using a modern browser. I see your point…

  3. Jeff Starr
    Jeff Starr 2009/12/13 3:12 pm

    Hey Tyler, absolutely – using a bit of JavaScript for the purposes of progressively enhancing your site with some advanced selectors or other CSS3 tricks is a great way to go about it. The way I see it, people who want the best experience on the Web will be using an updated version of one of the better browsers, Firefox, Opera, Safari, et al. It is unlikely that people visiting with old IE or other antiquated browsers will even notice the difference.

  4. Extending codes in your article sucks. I can’t see the whole code since it extends onmousemove action.

  5. Have you looked at the latest jQuery 1.4 changes? $.browser is being replaced by .support
    It would be great if you had a 1.4 update to this article.

  6. Jeff Starr
    Jeff Starr 2009/12/14 8:13 am

    @ufucuk: yes, I am aware of the issue and looking for a good solution. In the meantime, all you need to do is copy/paste the code into a text editor to take a look at it. Or read it in your feed reader.

    @Gustavo: Thanks for the heads up – I will update the article soon with a note about the replacement. Good call.

  7. Great looking site, but I’ve always been against requiring a second technology to fix the first when you CAN do it in the first.

    That being said, I think I like the method over at http://www.tvidesign.co.uk/blog/CSS-Browser-detection-using-jQuery-instead-of-hacks.aspx . With this your able to keep all of your CSS styles for each browser right next to each other, can keep all of your JS at the bottom of a document with out delaying rendering, and limit the number of network connections.

    Do you see any flaws in this logic?

  8. Jeff Starr
    Jeff Starr 2009/12/14 6:31 pm

    Hi Matt,

    Thanks for the comment. I completely agree about solving problems as simply as possible, but there are many cases where CSS is simply insufficient to meet the goals of a design (e.g., as discussed in the article). Not even with CSS hacks could I have created this theme (I tried!) – hence the JavaScript solution.

    As for the logic behind your recommended method, I think it sounds great. Of course either technique includes the JavaScript at the bottom of the document, and either is going to result in the same number of network connections. So not really much difference other than having everything prepackaged and ready to go.

    I guess it all comes down to personal preference. For this design, I really like having the granular control over each stylesheet. It’s just so clean and precise. With that external script you mention, I think it just would’ve been overkill.

    Even so, it looks like a great tool to have in the belt and I look forward to trying it out on future projects. Thanks for pointing it out.

  9. By the way, the expanding-on-hover code area is a wonderful idea, Jeff.

  10. Concur with Helen, the mouse-overs are way cool. I’ve been looking at them for a few weeks now, and I only just noticed that effect today- did you just enable it or have I been totally blind? Nicely done!

  11. wow this is such a useful tutorial, thanks for sharing on your blog! I know good tutorials aren’t easy to come by these days, but following this was so easy and it’ll be useful on my website

  12. thx a lot for the tricks !

Comments are closed for this post. Something to add? Let me know.
Welcome
Perishable Press is operated by Jeff Starr, a professional web developer and book author with two decades of experience. Here you will find posts about web development, WordPress, security, and more »
BBQ Pro: The fastest firewall to protect your WordPress.
Thoughts
Air finally clearing here in WA. Feeling grateful to breathe again. #oxygenmatters
Past week here in WA state has been hellish. So much smoke, like living in a chimney.
Now in September, I’m where I wanted to be in March.
Spent some time updating my article on unsafe characters, once again current with latest IETF specification.
Just realized that “Neo” is an anagram for “One”. As in, “he is the One” (The Matrix).
To get VLC app to load all songs (including subfolders), go to Preferences ▸ Show All ▸ Playlist ▸ Subdirectory behavior ▸ Expand.
Switching from PhotoShop to Affinity Photo is one of the most liberating work-related things I've done in 20 years.
Newsletter
Get news, updates, deals & tips via email.
Email kept private. Easy unsubscribe anytime.