I was wondering what an efficient algorithm would be in the following scenario:
Given a parsed set of css rules, eg.
p.pStyle{margin-bottom:20px;font-family:Arial;}
p{font-family:Verdana;}
p.anotherPStyle{margin-bottom:10px;}
from a css stylesheet, it is possible that several rule sets apply to a given element (say a <p class="pStyle anotherPStyle">hello</p>
in my document).
I need to determine what rules in the stylesheet apply to a given element firstly (so here that is p, pStyle and anotherPStyle
), and then create a Comparator that is able to sort the applicable rules by specificity (from most-specific to most-general). NOTE: I already have designed an algorithm to apply the rules once sorted so you needn't solve that problem efficiently.
I've been toying with several ideas, namely one that involves determining the level in the DOM tree that a given rule is specific to....Though I'm not sure if this is the correct way to go?
How does the browser engine do this efficiently? I'm looking to replicate it in Java, but am comfortable with many other languages so any code you can offer is most appreciated.
Thanks
Memorize how to calculate specificity! Start at 0, add 100 for each ID value, add 10 for each class value (or pseudo-class or attribute selector), add 1 for each element selector or pseudo-element. Note: Inline style gets a specificity value of 1000, and is always given the highest priority!
Inline styles added to an element (e.g., style="font-weight: bold;" ) always overwrite any normal styles in author stylesheets, and therefore, can be thought of as having the highest specificity.
Inline styles have the highest specificity. In our specificity weight system, they have a value of 1000. Let's try to make sense of it. The property values of selectors with a higher weight will always be applied over a selector with a lower weight.
1) Inline style: Inline style has highest priority among all. 2) Id Selector: It has second highest priority. 3) Classes, pseudo-classes and attributes: These selectors has lowest priority.
That is determined by specificity. In this case, since they are both equally specific, the declaration that comes last in the file, wins.
Specificity is calculated by ranking the different parts of the selector.
Ranked from most specific to least:
Where rank n > rank n+1
, regardless of how many points each rank has.
ul#nav li.active a
The points are:
Therefore, each property in that selector has a specificity value of [0,0,1,1,3]
(We'll get to that extra zero in a minute). That value is more specific than any selector, as long as it might be, without an ID, for example.
Comparison algorithm:
More important notes:
- The universal selector
(*)
has no specificity value (0,0,0,0) Pseudo-elements (e.g.:first-line
) get0,0,0,1
unlike their
pseudo-class brethren which get0,0,1,0
- The pseudo-class
:not()
adds no specificity by itself, only what's inside it's parentheses.- The
!important
directive can be applied on a single declaration, and adds a point to a "0th" rank, which is more specific than anything
else. So in the example above, adding!important
on any rule will
bump the specificity value for that rule only to[1,0,1,1,2]
,
granting it an instant win over any other rules without!important
.
See this great article on the subject
The way the browser does it, is to go over the selector from right to left, and filtering elements out of the DOM as they go.
Going back to the previous example:
ul#nav li.active a
The browser does the following:
a
element.li
element with an .active
class (this is through the descendant combinator: ancestor descendant
).ul
with an ID of #nav
(again, the descendant combinator is used).If all these conditions are met for a certain element, then the styles are applied to it.
You can read it:
Select any
a
element
with an ancestor with a class of.active
, which is also ali
,
which in turn has an ancestor with an ID of#nav
, which is also aul
.
You'll need to have a fully function and complete DOM tree to be able to successfully determine which element has what CSS styles.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With