Browser-Specific Styles with the Dojo Toolkit

By  on  

Every JavaScript library aims to cure the pain of dealing with cross-browsers JavaScript issues. The Dojo Toolkit takes that a step further by trying to help you deal with cross-browser CSS issues. Dojo features a file called "uacss.js" which adds CSS classes to the page's HTML element to allow you to more easily write browser-specific CSS. Lets take a look at how Dojo attempts to help us write more maintainable CSS.

The HTML Result

<html xmlns="http://www.w3.org/1999/xhtml" class="dj_gecko dj_ff3 dj_contentbox"> <!-- Firefox 3 / Gecko -->
<html xmlns="http://www.w3.org/1999/xhtml" class="dj_webkit dj_safari dj_contentbox"> <!-- Safari / Webkit -->
<html xmlns="http://www.w3.org/1999/xhtml" class="dj_webkit dj_chrome dj_contentbox"> <!-- Chrome / Webkit -->
<html xmlns="http://www.w3.org/1999/xhtml" class="dj_ie dj_ie8 dj_contentbox"> <!-- Internet Explorer 8 -->

All browser-specific CSS classes are added to the HTML element. How can you use these styles now?

The CSS Sample

.minHeight			{ min-height:600px; }
.dj_ie6 .minHeight	{ height:600px; } /* IE6-specific */

.dj_webkit .rounded	{ -webkit-border-radius:5px; }
.dj_gecko .rounded	{ -moz-border-radius:5px; }

All you need to do is place the browser-specific selector before the other piece of your selector.

The uacss.js JavaScript

dojo.provide("dojo.uacss");

(function(){
	// summary:
	//		Applies pre-set CSS classes to the top-level HTML node, based on:
	// 			- browser (ex: dj_ie)
	//			- browser version (ex: dj_ie6)
	//			- box model (ex: dj_contentBox)
	//			- text direction (ex: dijitRtl)
	//
	//		In addition, browser, browser version, and box model are
	//		combined with an RTL flag when browser text is RTL.  ex: dj_ie-rtl.

	var d = dojo,
		html = d.doc.documentElement,
		ie = d.isIE,
		opera = d.isOpera,
		maj = Math.floor,
		ff = d.isFF,
		boxModel = d.boxModel.replace(/-/,''),

		classes = {
			dj_ie: ie,
			dj_ie6: maj(ie) == 6,
			dj_ie7: maj(ie) == 7,
			dj_ie8: maj(ie) == 8,
			dj_quirks: d.isQuirks,
			dj_iequirks: ie && d.isQuirks,

			// NOTE: Opera not supported by dijit
			dj_opera: opera,

			dj_khtml: d.isKhtml,

			dj_webkit: d.isWebKit,
			dj_safari: d.isSafari,
			dj_chrome: d.isChrome,

			dj_gecko: d.isMozilla,
			dj_ff3: maj(ff) == 3
		}; // no dojo unsupported browsers

	classes["dj_" + boxModel] = true;

	// apply browser, browser version, and box model class names
	var classStr = "";
	for(var clz in classes){
		if(classes[clz]){
			classStr += clz + " ";
		}
	}
	html.className = d.trim(html.className + " " + classStr);

	// If RTL mode, then add dj_rtl flag plus repeat existing classes with -rtl extension.
	// We can't run the code below until the <body> tag has loaded (so we can check for dir=rtl).  
	// Unshift() is to run sniff code before the parser.
	dojo._loaders.unshift(function(){
		if(!dojo._isBodyLtr()){
			var rtlClassStr = "dj_rtl dijitRtl " + classStr.replace(/ /g, "-rtl ")
			html.className = d.trim(html.className + " " + rtlClassStr);
		}
	});
})();

You can see that this file is very key to Dojo's browser-specific CSS interactions. The classes object holds a list of possible CSS classes to add to the HTML element, ranging from browser names to browser versions and even "quirks mode" checking. The last step is to add those classes to the HTML element.

The one downside to using Dojo for your browser-specific CSS is that the user may not allow JavaScript. If your web application requires JavaScript and you're using Dojo, however, use Dojo's system of browser-specific CSS to create more readable CSS code!

Recent Features

  • By
    Camera and Video Control with HTML5

    Client-side APIs on mobile and desktop devices are quickly providing the same APIs.  Of course our mobile devices got access to some of these APIs first, but those APIs are slowly making their way to the desktop.  One of those APIs is the getUserMedia API...

  • By
    Regular Expressions for the Rest of Us

    Sooner or later you'll run across a regular expression. With their cryptic syntax, confusing documentation and massive learning curve, most developers settle for copying and pasting them from StackOverflow and hoping they work. But what if you could decode regular expressions and harness their power? In...

Incredible Demos

  • By
    background-size Matters

    It's something that makes all men live in fear, and are often uncertain of. It's never spoken, but the curiosity is always there. Nine out of ten women agree in the affirmative. Advertisers do their best to make us feel inadequate but...

  • By
    MooTools Accordion: Mouseover Style

    Everyone loves the MooTools Accordion plugin but I get a lot of requests from readers asking me how to make each accordion item open when the user hovers over the item instead of making the user click. You have two options: hack the original plugin...

Discussion

  1. good tut man :)

  2. I can’t help but think this is a very bad idea in general. Normally the only browser you need to target is IE, for which conditional comments work great. Past that, feature detection, not browser detection, is pretty much the accepted way to build web sites/applications. On top of the fact that browsers can spoof their user agents, I am trying to figure out how this could be useful.

    It seems you could build a site that would easily break with future browser updates by using this method.

  3. @Doug Neiner: I do like some of your points. If you’re married to Dojo, I still think this is very useful.

    Most would agree with you about user agent detection but I don’t. My feeling is that users who install plugins, etc. to spoof their UA know that the website may not work the same. I’m probably the minority there but it’s just how I feel.

  4. and this is some of the reasons why I go to a website and it looks aweful. This is a really bad idea. As Doug mentioned before you should NEVER target a specific browser (besides IE (always an exception))

    You can see this problem in effect in your code line #30.

    “// NOTE: Opera not supported by dijit ”

    Perfect example of the fail in this code. This also fails on the next versions of any browser that no longer need the hacks.

    You are just asking for more work and more errors in the future writing code like this.

  5. In practice, this is exactly how the uacss “sniff” gets used: a class hook for version-specific IE-targeted rules, and occasionally for rules targeting differing box models, or some janky FF or Safari bug. The other key value of this technique is for those use cases where you don’t own the entire page, so quirks/standards mode is not under your control, and adding conditional comments may also be out of the question.

    It’s also undoubtably handy for a quick hack, and while that might or might not come around to bite you in the long run, if you’ve never needed a quick targeted css fix, you’re living in some strange parallel universe I’ve not visited.

  6. This is a good method for browser-specific hacks, but I think parsing the useragent string with PHP might be a better way of going about it, since you already don’t care if someone has a spoofed useragent.

    It only takes 1 line of code for each browser, and you can just load in custom CSS styles.

    You might also like: http://www.modernizr.com/

  7. Buena esplicacion, nice man :-)

  8. Buena esplicacion, nice man :-)

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!