As many web developers know, you cannot detect OS and browser in CSS. But this is definitely needed because of little idiosyncrasies in layout, especially with fonts.

For example, on OSX Firefox, Helvetica Bold renders 2 pixels higher than every other browser, including Windows Firefox.

One solution for this is to write jQuery to fix specific css id or class top properties at runtime, but this becomes a nightmare to maintain, especially when you start dealing with rendering lists on-the-fly and have to call your css fix function every time the list changes.

I've come up with a simple and elegant solution that is 100% reliable and not only leaves the positioning in css where it belongs, it uses css in its intended way and makes it easy for you and your designer to tweak.

The basic idea behind it is to detect the os and browser and add them as classes to the body tag, and then write specific css around those classes.

This is requirejs formatting, and leverages jQuery, but even if you're not familiar with requirejs, you can grok how it works.

(function () {
  define(['jquery'], function($)
  {
    var Environment = {};
    Environment.isMac = navigator.platform.toLowerCase().indexOf('mac') > -1;
    Environment.isChrome = navigator.userAgent.indexOf('Chrome') > -1;
    Environment.isSafari = navigator.userAgent.indexOf('Safari') > -1 
                           && navigator.userAgent.indexOf('Chrome') == -1;
    Environment.isIE = $.browser.msie;
    Environment.isFirefox = $.browser.mozilla;
    Environment.isiOS = (navigator.userAgent.match(/(iPad|iPhone|iPod)/i) ? true : false);
    Environment.isAndroid = (navigator.userAgent.indexOf('android') > -1);
    var bodyClass;
    if (Environment.isiOS)
    {
        $('body').addClass('ios');
    }
    else if (Environment.isAndroid)
    {
        $('body').addClass('android');
    }
    else
    {
        if (Environment.isMac) $('body').addClass('osx');
        else $('body').addClass('win');
        var bodyClass;
        if (Environment.isChrome) bodyClass = 'chrome';
        else if (Environment.isFirefox) bodyClass = 'firefox';
        else if (Environment.isSafari) bodyClass = 'safari';
        else if (Environment.isIE) bodyClass = 'ie';
        $('body').addClass(bodyClass);
    }
    return Environment;
  })
})();

It detects the operating system and the browser and adds them as classes to the body tag. Then, in your css you can write specific css for a platform, a browser, or a platform+browser combination like this:

.osx .overlay-title {
    top: 18px;
}
.osx.firefox .meta-header span {
    top: 5px;
}
.chrome #import-button span {
    top: 39px;
}
.win.chrome .meta-header span {
    top: 3px;
}

This makes it super easy to fix those annoying cross-platform issues and keeps the presentation layer where it belongs, in the css. This same technique can also be used for localization. Enjoy!

 

4 Responses to Detecting operating system and browser with CSS

  1. Matt Stow says:

    In my opinion, your solution relies too much on browser sniffing and doesn't cater for Opera or edge cases, such as Firefox on Android. The sniffing isn't particularly advanced either.

    Relying on jQuery means that the user may see things re-adust as it gets loaded later than the styles and markup.

    I've written Layout Engine, a small vanilla JavaScript plugin which feature detects browser types, so you can easily target Firefox browsers for example: http://mattstow.com/layout-engine.html

    I'd also recommend using it in conjunction with CssUserAgent, which comprehensively sniffs for every browser, including allowing you to target specific versions: Get it here: http://cssuseragent.org

    HTH

  2. Mike McNally says:

    The jQuery "$.browser" object has been removed as of release 1.9.

  3. Steven Sacks says:

    The problem I'm trying to solve specifically is font vertical positioning. Modernizr is about capability, but the issue with font positioning is that some browsers (OSX Firefox is a particular pain) render certain fonts (even built-in ones like Helvetica) at slightly different positions.

    With the removal of $.browser, I'm going to have to simulate that functionality to deal with this issue. I don't know of any other way. I've tweeted @firefox about this stupid issue they have, but they've never replied.

  4. Steven Sacks says:

    Also, nobody uses Opera. ;)

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Set your Twitter account name in your settings to use the TwitterBar Section.