CSS specificity in JavaScript

Any JavaScript library worth its salt has a CSS selector engine, powering, amongst other things, an event system. I wanted to extend the idea of CSS specificity to events, so callbacks registered against the same element would be invoked in the order of their selector’s specificity, not the order in which the callbacks were registered.

For example, in Ignite 0.12, these two callbacks would be fired one after the other:

ignite.event.add('a','click',func1);
ignite.event.add('a.foo','click','func2');

For an anchor with the “foo” class, both selectors match, therefore func1 will fire, followed by func2. You must change the order of registration to change the callback sequence, which is obviously not feasible when dealing with modular code.

Instead, Ignite’s Event module 0.13 will fire common callbacks in order of specificity. This means you can insert a callback anywhere in the invocation sequence from any point in your code.

The code

So, just in case you ever needed to calculate a CSS specificity value (don’t all shout out at once), here’s a small JavaScript object to do just that:

var selector={
	specificity:function(s){		// accepts a single selector
		s=s.replace(/\([^\)]+\)/,"");
		return parseInt([
				/#[\d\w-_]+/g,
				/[\.:\[][^\.:\[+>]+/g,
				/(^|[\s\+>])\w+/g
				].map(function(p){
			var m=s.match(p);
			return m ? m.length.toString(16) : 0;
			}).join(''),16);
		},
	sort:function(s){			// accepts an array of selectors
		return s.sort(function(a,b){
			a=selector.specificity(a), b=selector.specificity(b);
			return a < b ? 1 : (a > b) ? -1 : 0;
			});
		}
	};

The selector.specificity() function returns a value corresponding to the CSS specificity. Because the values are arbitrary (in this case, they are calculated on a hex system to incorporate lengthier selectors), you can use selector.sort() to sort a series of selectors by their specificity.

var a=[
	"p span",
	"#foo",
	"div + ol li",
	];
selector.sort(a);  	// =>  ["#foo", "div + ol li", "p span"]
Posted October 3rd, 2009 in CSS, JavaScript.

One comment:

  1. Maureen Lyons:

    Thanks a million for this. Save me lots of time!
    Cheers,
    Maureen

Leave a response: