1

Possible Duplicate:
Sorting a set of CSS selectors on the basis of specificity

I need a JS library that order CSS selector texts from most specific selector text to the less specific selector text, where specificity is specified according to W3C

If there aren't any libraries out there, could I write it pretty simply using JS or jQuery?

CSS selector text could be div#body .text.

Community
  • 1
  • 1
einstein
  • 13,389
  • 27
  • 80
  • 110
  • What is *'specificty'* exactly? – Roko C. Buljan Jun 24 '12 at 21:28
  • @RokoC.Buljan, it's [defined by spec](http://www.w3.org/TR/CSS21/cascade.html#specificity). – josh3736 Jun 24 '12 at 21:30
  • Woho87, it's not clear what you're looking for - do you want a debugging tool that will show you a list of all the rules that are being applied to a particular element, in order from most to least specific? Or something totally different? (Also, I fixed the spelling to 'specificity' from 'specificty'.) – aem Jun 24 '12 at 21:40
  • Can you explain what exactly you want? I'm afraid this question will be closed without this info. – gdoron Jun 24 '12 at 21:43
  • I don't want any debugging tool. I'm creating a debugging tool:) I just need a library that order selector texts from most specific selector text to the less specific selector text, where specificity is specified according to http://www.w3.org/TR/CSS21/cascade.html#specificity – einstein Jun 24 '12 at 21:43
  • Ok updated the text. I hope you get it. – einstein Jun 24 '12 at 21:48
  • question makes no mention of what this library should do, or how it would be used – charlietfl Jun 24 '12 at 21:50
  • @charlietfl: "what this library should do" is plastered all over the question, especially after the edit... – BoltClock Jun 24 '12 at 21:51
  • @BoltClock notify my when you write one yourself. – einstein Jun 24 '12 at 22:02
  • My comment got auto-deleted, reposting: unfortunately all I have in the duplicate question is a rough pseudo-code solution, and no implementation details. I haven't heard of any libraries that do this yet, so I may very well end up writing one myself soon. – BoltClock Jun 24 '12 at 23:31

2 Answers2

1

In the comments on your question, josh3736 links the W3C specification for determining specificity. If you felt inclined to write such a library yourself (which I'd encourage, if for no other reason than learning more about it), their method seems like a good reference.

A selector's specificity is calculated as follows:

  • count 1 if the declaration is from is a 'style' attribute rather than a rule with a selector, 0 otherwise (= a) (In HTML, values of an element's "style" attribute are style sheet rules. These rules have no selectors, so a=1, b=0, c=0, and d=0.)
  • count the number of ID attributes in the selector (= b)
  • count the number of other attributes and pseudo-classes in the selector (= c)
  • count the number of element names and pseudo-elements in the selector (= d)

The specificity is based only on the form of the selector. In particular, a selector of the form "[id=p33]" is counted as an attribute selector (a=0, b=0, c=1, d=0), even if the id attribute is defined as an "ID" in the source document's DTD.

Concatenating the four numbers a-b-c-d (in a number system with a large base) gives the specificity.

eplawless
  • 4,225
  • 7
  • 34
  • 35
1

I figured I'd give this a stab. Feel free to use, modify (or fix) this code as you see fit. I can't promise it's correct, but the examples they give on the w3c spec all produce the same results.

function specificity(selector, isStyleAttribute) {

    selector = selector || "";
    function numMatches(regex) {
        return (selector.match(regex)||[]).length;
    }

    var numClasses = numMatches(/\.[\w-_]+\b/g);
    var numIds = numMatches(/#[\w-_]+\b/g);
    var numNamesInBraces = 0;
    var namesInBraces = selector.match(/\[[^\]]*\b[\w-_]+\b[^\]]*\]/g) || [];
    for (var idx = 0; idx < namesInBraces.length; ++idx) {
        numNamesInBraces += (namesInBraces[idx].match(/\b[\w-_]+\b/g)||[]).length;
    }

    var results = [0,0,0,0];
    results[0] = isStyleAttribute ? 1 : 0;
    results[1] = numIds;
    results[2] = numMatches(/\[[^\]]+\]/g) + numClasses;
    results[3] = numMatches(/\b[\w-_]+\b/g) - numIds - numClasses - numNamesInBraces;
    return results.join(',');

}

If you want to sort an array with it, it can be used like this:

selectors.sort(function(a,b) { return specificity(a) > specificity(b); });
eplawless
  • 4,225
  • 7
  • 34
  • 35
  • Inline styles don't have selectors - you would have to pass nothing as the first parameter and skip all of these checks altogether. In the duplicate question I link to, I provide a skeleton which covers most of the parts, but then again I might end up implementing something completely different from what I had originally planned... – BoltClock Jun 24 '12 at 23:25
  • I can merge your answer into the other question if you'd like. – BoltClock Jun 24 '12 at 23:39