Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Order by CSS Specificity

My main goal is to try to reorder a CSS style block based on specificity. I previously had helped from SO and I managed to produce this function. See gist.

Here is an example:

function specificity($selector){
// https://gist.github.com/2774085
}

$compare = function($a, $b) use ($specificity) {
    return $specificity($a) - $specificity($b)
};

$array = css_array();

uksort($array, $compare);

The above has been working great until I came across this CSS:

html, body, body div{
    background: transparent;
}
body {
    background-color: #D96F02;
}

This gets reordered into this:

body { // 1 point
    background-color: #D96F02;
}
html, body, body div{ // 4 points
    background: transparent;
}

However, this isn't how the browser applies the CSS.

I think my specificity function may be missing the importance of order of CSS rather than ordering based on selector specificity? Is this true?

Update

I think what I should do is in my compare function, I should always add an extra points of say 10 because specificity isn't just based on selectors its based on the order of the selector too. So something like this:

 $compare = function($a, $b) use ($specificity) {
        return ($specificity($a) + 10) - $specificity($b)
    };

How does this look and how do I determine number of points to give in this case!?

like image 266
Abs Avatar asked May 23 '12 09:05

Abs


1 Answers

The problem should go away if you serialize

html, body, body div{ 
    background: transparent; 
} 

as separate rules, as if they were written in the following manner:

html{ 
    background: transparent; 
} 
body{ 
    background: transparent; 
} 
body div{ 
    background: transparent; 
} 

The semantics is a bit confusing, but basically you are judging an entire declaration based on independent selectors that have been combined into the same rule set.

Re your update: specificity is not affected by selector order, i.e. the rules below have the same specificity. The last rule will take precedense rendering in blue, unless you re-arrange the rules rendering in red:

<style>
    #container span {color:red;}
    div #content {color:blue;}
</style>

<div id="container"><span id="content">Hello world!</span></div>
like image 132
Oleg Avatar answered Oct 23 '22 16:10

Oleg