Specificity rules for comma delineated lists

2019-04-11 10:44发布

问题:

When using Cascading Style Sheets I have observed the order of specificity as follows:

1st Laws: In-line Styles
2nd Laws: Number of ID Selectors
3rd Laws: Number of Class Selectors
4th Laws: Number of Element Selectors

So, items with in-line styles came first, followed by declarations with one or more ID selectors, followed by declarations with one or more class selectors, followed by declarations with one or more element selectors. With more IDs, classes and elements meaning more precedence, respectively.

From this viewpoint I was unable to comprehend where comma delineated lists of IDs, classes or elements fit. Does a comma delineated list have any special precedence rules? Also, in a single comma delineated list, are IDs, classes and elements considered separate items, for the purposes of calculating specificity?

Code example:

html, body, header {
  position: absolute;
  top: 0px;
}
header {
  position: relative;
  top: 50px;
}

What takes precedence in the above example? Is the comma delineated list treated as referencing a single element, in which case the header would take precedence simply for being last in the cascade, or is the comma delineated list treated as multiple elements, and therefore takes precedence? Or are there other rules I should be considering first?

回答1:

Remember that CSS is cascading - meaning the style that is referenced FURTHER down a CSS file will take precedence assuming the selector is the same:

header {
  background-color: red;
}
p, span, header {
  background-color: yellow;
}
<header>
  HEADER
</header>

If we switch around the declarations above, the opposite happens:

p, span, header {
  background-color: yellow;
}
header {
  background-color: red;
}
<header>
  HEADER
</header>

As you can see, comma separated selectors / declaration make no difference - they're treated the same as if you'd done them singly.



回答2:

Does a comma delineated list have any special precedence rules?

Strictly speaking, a selector-list does not have its own specificity value, but for the purposes of the cascade, the specificity of a selector-list is equal to the specificity of the most specific selector that matches the element. This is not stated explicitly in the current specification, but it appears in selectors-4. Even so, since a selector-list is nothing more than a way to combine two or more selectors in a single expression without having to repeat their style declarations, it makes sense why it would work this way.

Remember that a selector is only relevant to an element when it matches the element — otherwise, it never enters into specificity calculations, or any part of the cascade.

Also, in a single comma delineated list, are IDs, classes and elements considered separate items, for the purposes of calculating specificity?

Every simple selector has its own specificity value, but these values are added up at the complex-selector level. A complex selector is one part of a selector-list. For example, the selector-list

.foo > .bar, nav input:checked + label

has two complex selectors:

  1. .foo > .bar, with a specificity of (0, 2, 0)
  2. nav input:checked + label, with a specificity of (0, 1, 3)

What takes precedence in the above example? Is the comma delineated list treated as referencing a single element, in which case the header would take precedence simply for being last in the cascade, or is the comma delineated list treated as multiple elements, and therefore takes precedence?

In your example, the selector-list html, body, header consists of three separate lone type selectors. Since every element can only be of one element type at a time, it's easy to deduce that all three selectors in the list are mutually exclusive, i.e. an element can only match one of any of the three selectors at a time (or none at all). A header element can never match the html or body selectors, and so neither of those selectors is relevant. You just have the header selector to deal with, and specificity becomes less of an issue in your example. The result is that your second rule, with just the header selector, takes precedence, because the only two selectors that are relevant are equally specific.

But this becomes more pertinent when you have a selector-list that consists of more than one selector that can match the same element. Let's pretend that both selectors in my example above can match the same label element. So we have two selectors of specificity (0, 2, 0) and (0, 1, 3) that both match the same element. As in the first paragraph of my answer, the specificity is equal to that of the most specific selector, (0, 2, 0). It is not, as one might otherwise have guessed, the total specificity of all matching selectors (0, 3, 3), or the specificity of the least specific (which wouldn't really make sense anyway).

This means, for example, that a separate rule with a selector whose specificity is (0, 3, 0) will still take precedence over the selector-list, even if both selectors in that list match the same element. Consider this contrived example (you'll rarely find examples of this in the wild):

.foo > .bar.baz {
  color: red;
}

.foo > .bar, nav input:checked + label {
  color: blue;
}
<nav class="foo">
  <input type="checkbox" id="check" checked>
  <label for="check" class="bar baz">Checkbox</label>
</nav>

Notice that regardless of whether the checkbox is checked, the label never turns blue. This is because .foo > .bar.baz has a specificity of (0, 3, 0) which is higher than each of the two individual specificities given above, even though it's lower than the combined specificity, since specificities are never combined this way.



回答3:

In CSS separating rules by , means listing multiple selectors. So html, body, header style will be applied to every html, body and header no matter if some of it is missing or not. It will not provide any precedence to selector.

In your example header position will be absolute just because first rule will have lower precedence than second. Same as:

header {
    position: relative;
}

header {
    position: absolute;
}


回答4:

I this case both of them are Element Selectors so the outputted css would be bottom one because css is rendered from top to bottom precedence in this case takes last element.