CSS: User Agent Selectors

Gone are the days of CSS hacks for browsers...wait, no they're not. There are still little rendering hiccups in both major and minor versions of Safari, Chrome, Firefox, Internet Explorer. The hacks to target those newer browsers are few and far between.

Just recently, I ran across a radial gradient bug found only in Chrome 13.0x. Good luck searching for a CSS filter to apply a style purely for that browser. Good luck trying to use Modernizr to detect the glitch in gradient rendering. This was a specific bug to a specific version of a specific browser. What I wanted was a Modernizr-ish way of using CSS to swap out an image for a radial gradient, but only for that version of Chrome. I'm sure you're feeling me here. I'm sure you've hit some similar snags.

The thing is, some of all the old hacks work just fine on older browsers: IE6/7 hacks. I found it harder to find hacks for the newer browsers because, yes, you guessed it, they typically are better — so less vulnerabilities, less hacks. I came up with this snippet of code to help me with newer browsers.

<html>
    <head> … </head>    
    <body>
        <script>
            var b = document.documentElement;
              b.setAttribute('data-useragent',  navigator.userAgent);
              b.setAttribute('data-platform', navigator.platform );
              b.className += ((!!('ontouchstart' in window) || !!('onmsgesturechange' in window))?' touch':'');
        </script>
        …
    </body>
</html>

Enter the code. What you need to know about the snippet of code is that it produces output like this:

<html 
    data-useragent='Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1' 
    data-platform='MacIntel'>

Or for IE9, code like this:

<html 
    data-useragent='Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C)'
    data-platform='Win32'>
    ...
</html>

Oh, but it gets more interesting. Now we can target iPads easily. How so?

<html 
    data-useragent='Mozilla/5.0(iPad; U; CPU iPhone OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B314 Safari/531.21.10'
    data-platform='iPad'>
    ...
</html>

Now, voila! I have an attribute. And guess what? I can use CSS attribute selectors to style something. Let's look at a snippet of CSS that will fix that Chrome issue I had.

html[data-useragent*='Chrome/13.0'] .nav{
    background:url(img/radial_grad.png) center bottom no-repeat;
}

Using the *= wildcard attribute selector, I can now match any portion of the string, in this case, I wanted to target the useragent of Chrome 13.0x. If I wanted to apply the fix only to Chrome 13.0x browsers on Windows, I'd simply use a rule like html[data-useragent*='Chrome/13.0'][data-platform='Win32']. Want to target iPad? Easy business, friend. Just use html[data-platform='iPad'].

Last, you may have noticed the "touch" class. Yup, you can use that class to target touch devices. For instance, let's say you wanted to make an action appear on :hover in your application. You might have some CSS like this:

li .action{
    opacity:0;
}
li:hover .action{ 
    opacity: 1;
}

But, touch devices don't have :hover. Using the boilerplate addon, with one line of CSS, you'll be covered:

.touch li .action{
    opacity:1;
}

And that's it! Feel free to use this code however you see fit. Let me know if you see a better way this could be implemented :)

css design html