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
That is determined by specificity. In this case, since they are both equally specific, the declaration that comes last in the file, wins.
Specificity Calculation
Specificity is calculated by ranking the different parts of the selector.
Ranked from most specific to least:
Style attribute - If the rule is found in a style attribute, this rank gets 1.
ID - For each ID found in the selector, this rank gets an additional 1.
Classes, Pseudo-Classes, Attribute selectors - For each one found in the selector, this rank gets an additional 1.
Elements - For each element found in the selector, this rank gets an additional 1.
Where rank n > rank n+1, regardless of how many points each rank has.
Example
ul#nav li.active a
The points are:
0 - Not a style attribute.
1 - 1 ID found.
1 - 1 Classname found.
3 - 3 Elements found.
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:
Go from left to right on the ranks.
Compare the ranks on both selectors.
The rank with the higher amount of point, wins.
If the ranks are equal, continue right to the next (less specific) rank.
If all ranks are equal, the one which comes later in the CSS document, wins.
More important notes:
The universal selector (*) has no specificity value (0,0,0,0) Pseudo-elements (e.g. :first-line) get 0,0,0,1 unlike their
pseudo-class brethren which get 0,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.
Extra Reference
See this great article on the subject
How to determine which styles go to what element
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:
Take an a element.
Now check if it has an ancestor that is a li element with an .active class (this is through the descendant combinator: ancestor descendant).
Now check if it has a higher ancestor that is a 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 a li,
which in turn has an ancestor with an ID of #nav, which is also a ul.
You'll need to have a fully function and complete DOM tree to be able to successfully determine which element has what CSS styles.
Related
What is the difference between these two CSS selectors?
#someId
a#someId
It appears to work like the . selector would. The first selector means "select the element with the ID someID." What does the second one mean? Am I right to think it means "select the a element with ID someID"? Given that there can only be one element with a given ID on a page, what is the purpose behind specifying the tag? Does the second selector get a higher specificity?
Yes, the second selector has higher specificity.
#someId is just a single ID and will select any element with that ID regardless of what element it is. a#someId is both an element and an ID, making it more specific as it will only select anchor a elements with that ID.
There is a common trick to calculating specificity and comparing the specificity of different selectors, which is to count the IDs, classes, and elements like X,X,X. The most specific selector is the one with the highest leftmost number (if that is a tie, move to the next number).
#someId is just an ID, so it's 1,0,0.
a#someId is an ID and an element, so it's 1,0,1 and therefore more specific.
IDs are always more specific than classes and classes are always more specific than elements. Psuedo-elements count as elements and psuedo-classes count as classes for the purposes of calculating specificity. Technically 256 elements = 1 class and 256 classes = 1 ID, but if you ever have that much going on in a selector string you have way bigger problems to worry about.
The only thing more specific than an ID (besides a selector string containing several IDs) is a style with !important or an inline style declared via the style attribute on the element.
More about CSS Specificity:
Specifics on CSS Specificity (CSS Tricks)
CSS Specificity (Smashing Mag)
CSS Specificity (MDN)
Understanding CSS Specificity (Nettuts)
It means,
select an a element having an id someId
Yes, it's more specific.
#someId
Selects the element with the id 'someId'
a#someId
Selects the anchor element with the id 'someId'
The first is the better approach on the assumption you are using unique ids as is recommended, as well as the fact it executes faster (CSS resolves right to left)
This is not a question about being specific enough when ids are included, in which case only the id selector should be used. However, if class name or nesting were present, greater levels of selection helps more accurately target specific elements. However, dont forget that overkill is just as bad as underkill- its all about balance.
The second form a#someId is overkill, as theoretically there should be no two elements with the same id in the document.
One reason I can think of using it would be if you had an element in the page that changed type but maintained the same id through some Javascript manipulation, and you wanted some CSS for that particular ID.
e.g. with some jQuery:
<style>
p#someId { ....}
a#someId { ....}
</style>
<script>
$('#someID').replaceWith( '<a id="someId">Now a link</a>');
</script>
....
<p id='someId'>Not a link</p>
In my stylesheet, .four-across li defines width: 174px; at line 8806. Below that rule at line 9603, .no-search-results defines width: auto;. However, the 174px rule is overriding an element with .no-search-results. Why would that be?
You should read about CSS specificity.
.four-across li is more specific than .no-search-results, so it have higher importance level.
Specificity is calculated by counting various components of your css
and expressing them in a form (a,b,c,d). This will be clearer with an
example, but first the components.
Element, Pseudo Element: d = 1 – (0,0,0,1)
Class, Pseudo class, Attribute: c = 1 – (0,0,1,0)
Id: b = 1 – (0,1,0,0)
Inline Style: a = 1 – (1,0,0,0)
by Understanding Style Precedence in CSS: Specificity, Inheritance, and the Cascade
Document order matters only when given specificity is exactly the same. In you example first selector is (0,0,1,1) and second is (0,0,1,0), so the first one overrides the second one, no matter how are they ordered within CSS document.
Read:
Reviewing CSS Style Priority Level
Understanding Style Precedence in CSS: Specificity, Inheritance, and the Cascade
In this case it's because a class and an element type are more specific than just a class, and it's favored over the order.
Two reasons:
The last rule scanned has precedence over those scanned previously, all else being equal.
The more specific the rule is (two specifiers as opposed to one) the higher the precedence.
I have a jsbin with a table of inputs, using bootstrap. What confuses me is that the style with
input.someClass {
background-color: blue;
}
is applied, as expected, but
.anotherClass {
background-color: green;
}
is not applied to my input elements. What is the reason for this? For reference, check out http://jsbin.com/enaris/3/edit
What is the reason for this?
It's simply a matter of specificity - the first selector has a type selector attached to the class name whereas the second selector only has a single class. The second selector is therefore more specific and takes precedence.
This is migrated from another answer of mine, it may help:
You can think of specificity as four numbers, starting with (0,0,0,0):
!important rules always take precedence, only another !important rule
can override a previous one (its an accessibility feature of CSS,
designed to override the UA stylesheet)
The universal selector (*) has a specificity of 0
Combinators like + and ~ also have no specificity
Inline styles have the highest specificity (other than !important)
and count as the first number (1,0,0,0)
ID's (#test) count as the second number in the above set (0,1,0,0)
Classes, pseudo-classes and attribute selectors are the third number
(0,0,1,0)
Type selectors and psuedo-elements (e.g. - <p> & ::after) take place of the
fourth number, and are the least specific
Remember that if two rules have the same specificity and specify the
same property the latter in the stylesheet will win
Based on the above, the first selector has a specifictiy of (0,0,1,1) while the second only has (0,0,1,0)
CSS rules are applied from least specific to most specific.
You have:
Least Specific More Specific Most specific
.anotherClass input[type=...] (bootstrap) input.someClass
So, in your example b-cell is more specific than bootstrap styles and a-cell is less.
You can force a-cell to take precedence with !important (but use !important with caution, as it might become a debugging hell):
.a-cell {
background-color: green !important;
While trying to reduce the HTML size of a web page, I've come across suggestions by Google and the PageSpeed Firefox Add-On regading efficiency of CSS selectors that (almost) made me reconsider the changes:
http://code.google.com/intl/de-DE/speed/page-speed/docs/rendering.html#UseEfficientCSSSelectors
Specifically, descendant selectors are great for selecting a whole block (e.g. DIV) using an ID or CLASS attribute and then keeping all of its child elements free of CLASS/ID attributes. But if the order of traversal for applying the rules is as described by Google, they should not be used:
Descendant selectors are inefficient because, for each element that matches the key, the browser must also traverse up the DOM tree, evaluating every ancestor element until it finds a match or reaches the root element. The less specific the key, the greater the number of nodes that need to be evaluated.
I very much doubt that browsers use such an inefficient order of traversal, surely they would only process subtrees of elements that match the top selector component, i.e. in #foo span {...} only elements below #foo should be checked and not every single span. Can anyone who has looked at recent browser code confirm/deny this?
The second questionable suggestion is about overly qualified selectors:
ID selectors are unique by definition. Including tag or class qualifiers just adds redundant information that needs to be evaluated needlessly.
If ID selectors are unique by definition, why would browsers need to check the redundant information? I know that they do because for example,
div#foo { color: black; }
#foo { color: white; }
will result in black text in a <div id=foo>, but a) it should not be done(? W3C reference needed) and b) I don't see why it would be noticeably slower when it results in a simple O(1) check of the element's tag name.
Can anyone on good terms with modern browsers' source code shed some light on these claims? Since most modern sites use descendant selectors (including SO) and they have clear advantages, I'd very much like to use them...
Edit:
I've experimented a bit with generated pages and it seems that the browsers' handling of descendant selectors is indeed pitiful:
A page consisting of (abbreviated):
#top a {text-decoration: none;}
#foo1 a.foo {color: red;}
#foo2 a.foo {color: red;}
[... repeated 10000 times]
<body id=top>
<div>...[nested 50 times]<a href=foo>bla</a></div>[...]
[previous line repeated 10000 times]
(basically 10000 lines with 50 nested divs each to traverse till the root node and 1 selector that matches out of 10000)
loads and renders (time till window.onload() executes) in 2.2 seconds using Safari 5 and just under 10 seconds with Firefox 3.6.10.
When the .foo class selector is removed from the non-applying rules, the page takes around 200 seconds with Safari 5 and 96 seconds with Firefox 3.6.10. This illustrates how badly the descendant selectors are implemented (in that case, each of the 10000 rules probably causes a traversal till #top, where the rule fails).
How do child selectors fare? #foo > span > div > div > div > div > div a {color: red;} (also never matches but forces traversal of 6 parent nodes) takes 27 seconds with Safari 5 and 31 seconds with Firefox 3.6.10.
Conclusion
Descendant and child selectors both suck currently on major browsers. It's still better to add ugly class/id attributes to all your styled tags if you care about speed, at least for very common HTML tags (such as a, img, div etc.).
Have a look at this recent post by Jonathan Snook: http://snook.ca/archives/html_and_css/css-parent-selectors
You'll see how browsers evaluate expressions and the reasoning behind why certain selectors are inefficient.
A relevant quote from the post:
CSS gets evaluated from right to left.
To determine whether a CSS rule
applies to a particular element, it
starts from the right of the rule and
works it's way left.
If you have a rule like body
div#content p { color: #003366; } then
for every element—as it gets rendered
to the page—it'll first ask if it's a
paragraph element. If it is, it'll
work its way up the DOM and ask if
it's a div with an ID of content. If
it finds what it's looking for, it'll
continue its way up the DOM until it
reaches the body.
By working right to left, the browser
can determine whether a rule applies
to this particular element that it is
trying to paint to the viewport much
faster. To determine which rule is
more or less performant, you need to
figure out how many nodes need to be
evaluated to determine whether a style
can be applied to an element.
Big bold caps-lock TL;DR:
I KNOW HOW SELECTOR SPECIFICITY IS DETERMINED, I THINK IT USES FLAWED ASSUMPTIONS AND I CAN BACK MY IRRITATIONS UP WITH VALID SET THEORY RELATIONS, PLEASE DO NOT RESPOND EXPLAINING W3 CALCULATION RULES FOR SPECIFICITY, PLEASE READ THE QUESTION <- read that.
This has bothered me for some time, when I write a style for some HTML that would be similar to below:
...
<div id="outer">
<span id="inner"></span>
<span></span>
...
</div>
...
Why would specificity rules make the selector "#outer span" more specific than "#inner"?
ID's are unique, so when I say "#inner" I can ONLY be referring to one element, so why is it less specific? I understand the rules on determining specificity, I just wonder if this was intentional or accidental, also if anyone knows how I can ask this question to the people who write the css standards.
I should note, I do understand that I COULD use #outer #inner to ensure maximum specificity, but that seems like it defeats the purpose of ID in the first place. This also is a problematic solution for when I write templates and I'm not sure that one ID will be inside of another. I'm not looking for a workaround, just a theory answer.
My question is theory, entirely based on set logic. The though I have is that if you define a rule for 1 item of n possible items, isn't that as specific as you can go? Why would the creators of CSS selectors make a rule that could define m items of n possible items, where m is a subset of n as a more specific rule?
My thought is that #id would be the equivalent of identifying 1 item by name, and #id elm would be identifying a group by its relation to an item by name. It's completely counter intuitive to call a named item less specific than an unnamed group with a named relation.
I think the idea of "why" is more a "generational" or "authority" view point. If #Parent (of any generation back) says all my children who meet qualification "x" (in your case, span) are going to be given an inheritance of "y" (whatever css property), it doesn't matter what the single individual #Child wants, it needs the authority of the #Parent to get it if the parent has stated otherwise.
Added on edit: The inline style would then be the rebellious child, and the !important the crack down parent. Edit: I kept this for humor, but I don't think it reflects the idea as well as my later statement below.
Added on edit to question in comment: Given:
#outer span ...
#inner (which is a span element)
Then to help insure #inner selection I recommend:
body span#inner (*edit:* just span#inner works *edit:* if defined later)
or give body an id and
#bodyId #inner
Of course, these can still be overridden. The more "generations" involved, the more it becomes difficult to change the behavior because of the generational consensus (if great grandpa and grandpa and parent are all in agreement, it's likely the child is not going to get away with doing his own thing).
I had to majorly rewrite this section on later edit
Given this HTML:
<div id="grandparent">
<div id="parent">
<div id="child"></div>
</div>
</div>
I had previously stated that "#parent div has greater authority than #grandparent div. Both have generational authority, in fact, an 'equal' generational authority, but the first is 'nearer' generation" wins. The error in that is that "nearer" generationally is not what matters, but rather last to be granted authority. Given equal authority powers, the own designated last is the one that wins.
I believe I can still stand by this statement: With that thought in mind, a selector like #child[id] (which outweighs both previous selectors) treats its attributes as permissions for greater authority to rule that which itself controls. Having the # already gave it authority, but not enough to override a # of a earlier generation if that earlier generation also carries another selector granting more authority.
So #grandparent div outweighs #child but not div#child if it is last to receive authority [added this], and not #child[id] because the [id] adds greater authority for the #child to rule itself. If equal selectivity then last one to be granted authority wins.
Again, the style attribute setting a style property itself really acts more like a supreme granting of authority to rule oneself, assuming something more "!important" doesn't take it away.
As a summary statement to answer "why" it is this way (and not in line with "set" theory), I believe it is not about accuracy or really even specificity (though that is the term used) as indeed then one would expect #ChildsName to be the final unique say in the matter because nothing more specific need be said. Rather, however, while the documentation may not state it as such, "selectivity" is really structured on a granting of authority. Who has the most "rights" to rule the element, and given a "tie", who was the last one to be granted those rights.
Because #outer span has both an ID selector and an element selector. That element selector is what makes it weigh more than #inner.
The former means 'select any element found within any element of ID outer'.
The latter means 'select any element with ID of inner'. It doesn't know where #inner is in your HTML document, hence less specificity.
Perhaps you could either try #outer #inner or span#inner try #outer span#inner instead.
How
W3C rules for calculating specificity:
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.
Also, when rules have the same specificity, the last one wins.
Example
outer span: a=0, b=1, c=0, d=1 --> 101
span#inner: a=0, b=1, c=0, d=1 --> 101
div#outer span#inner: a=0, b=2, c=0, d=2 --> 202
Try rearranging rules 1 and 3: http://jsfiddle.net/Wz96w/
Why
My thought is that #inner does not specify a unique element. While it is only 1 element per page, that ID could be a completely different element on another page.
One page:
<div id="outer">
<div id="inner"> ... </div>
</div>
Another page:
<ul id="outer">
<li>main1
<ul id="inner">
<li>sub1</li>
<li>sub2</li>
</ul>
</li>
<li>main2</li>
</ul>
Although, I would not code it this way. I think it explains why adding the element (ul#outer vs. #outer) is worthy of extra specificity.
For the point on descendants, I'm visualizing the DOM for your markup. The rule #outer span has a path length longer than that of #inner. Therefore, in the case, it specifies a more specific subtree, so it should be awarded more specificity (and #outer #inner li should be [is] worth more than #inner li).
To me, and I base this entirely on opinion, it's the expected "natural" behaviour.
Consider this:
You know how CSS specificity is calculated, and from that formula we know that #outer span is more specific than #outer, which is necessary for CSS on the whole to work correctly, and it makes sense. #outer span is also more specific than #inner, which is also logical within the domain of the stylesheet (#inner is only an ID, and #outer span is an ID plus an element, so in order to rank them if we are just looking at the stylesheet, the more qualified one must be more specific).
What's happening here is that you're applying the context of the HTML markup, and saying "Well, that doesn't make sense." To make things work the way that you're expecting, the browser would have to consier the following:
This <span id="inner"> is inside <div id="outer">
The stylesheet rules for #outer span and #inner apply
The rule #outer span is more specific than #inner
But wait! <span id="inner"> is inside <div id="outer">, so ignore the calculations based on the stylesheet and claim that #inner is more specific
That last step makes the determination process entirely based on the structure of the HTML, which makes it impossible to define the specificity in terms of the CSS alone. I personally believe that this would make the entire process more convoluted and hard to define, but you may disagree.