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 c开发者_Go百科ould 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 try #outer #inner
or span#inner
#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.
精彩评论