Specificity Rules for Comma Delineated Lists

Specificity rules for comma delineated lists

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>

CSS specificity of comma-separated group selector

In your first example you have ONE selector. It is a selector comprised of multiple simple selectors separated by descendant combinators. But it is still one selector.

In your second example you have FOUR selectors. The comma separates selectors.

§5. Groups of
selectors

A comma-separated list of selectors represents the union of all
elements selected by each of the individual selectors in the list.

For example, in CSS when several selectors share the same declarations,
they may be grouped into a comma-separated list.

Specificity applies to a single selector, so in your second example, which represents four distinct selectors, you need to calculate the specificity for each one separately.

Think about it this way:

The purpose of specificity is to establish which CSS rule gets applied to an HTML element when there are multiple selectors targeting the same element.

.intro {
border: 2px dashed red;
}

div {
border: 1px solid black;
}
<div class="intro">text</div>

Calculating specificity of multiple selectors on one rule

I suspect your confusion comes from the assumption that when you group multiple selectors, you can manipulate the specificity of the selectors that are contained within the comma-separated list. This is not true: the comma-separated selector list is simply a shorthand to declare the same styles that are applied to all your selectors.

In other words:

#box1 div.spec2 p,  /* Specificity: 0, 1, 1, 2 */
#box1 #box2 p { /* Specificity: 0, 2, 0, 1 */
color: blue;
}

#box1 #box3 p { /* Specificity: 0, 2, 0, 1 */
color: green;
}

...is actually equivalent to:

#box1 div.spec2 p { /* Specificity: 0, 1, 1, 2 */
color: blue;
}

#box1 #box2 p { /* Specificity: 0, 2, 0, 1 */
color: blue;
}

#box1 #box3 p { /* Specificity: 0, 2, 0, 1 */
color: green;
}

CSS !important rule with list values

You need to place the !important at the end, prior to the closing semi-colon.

Note that it works to override the property value as a whole, not individual components of it- so it cannot be applied to the individual comma separated arguments (indeed, this would be a pointless exercise as you'd logically only then need a single argument, the one you are making important).

That said, note as per MDN, the use of !important is not recommended:

The !important exception

When an !important rule is used on a style declaration, this
declaration overrides any other declaration made in the CSS, wherever
it is in the declaration list. Although, !important has nothing to do
with specificity. Using !important is bad practice because it makes
debugging hard since you break the natural cascading in your
stylesheets.

Some rules of thumb

  1. Never use !important on site-wide css.

  2. Only use !important on
    page-specific css that overrides site-wide or foreign css (from ExtJs
    or YUI for example).

  3. Never use !important when you're writing a
    plugin/mashup.

  4. Always look for a way to use specificity before even
    considering !important

Can we achieve anything with the new CSS :is() pseudo-class that we can't already achieve with comma-separated queries?

You are actually dealing with basic examples but consider more complex ones like the following:

.box h1, .box h2, .box h3, .box h4

In order to avoid repeating the .box we use

.box :is(h1, h2, h3, h4)

As far as I know, this was the main motivation for :is(): avoid rule duplication.

Another common example is the table selectors:

table tr td, table tr th

now will become

table tr :is(td, th)

What do commas and spaces in multiple classes mean in CSS?

.container_12 .grid_6,
.container_16 .grid_8 {
width: 460px;
}

That says "make all .grid_6's within .container_12's and all .grid_8's within .container_16's 460 pixels wide." So both of the following will render the same:

<div class="container_12">
<div class="grid_6">460px Wide</div>
</div>
<div class="container_16">
<div class="grid_8">460px Wide</div>
</div>

As for the commas, it's applying one rule to multiple classes, like this.

.blueCheese, .blueBike {
color:blue;
}

It's functionally equivalent to:

.blueCheese { color:blue }
.blueBike { color:blue }

But cuts down on verbosity.

first-letter pseudo element overriding higher specificity rules

This is not a specificity issue. You are simply dealing with different elements here - granted, one of them is just a pseudo element, but still.

Specificity only comes into play when several rules are matching the same element(s) - not the case here.

It is pretty much the same as if you had the following:

html .red { /* html in front to increase specificity */

color: red;

background-color: grey;

}

.first-letter { /* replaced pseudo element with a class and a "real" element here */

color: orange;

background-color: black;

}
<div class="red"><span class="first-letter">R</span>ED</div>

Why do CSS comma separated selectors break entire rule when one part is unknown?

It turns out this is actually intentional and defined in Selectors Level 3 (emphasis by me):

If just one of these selectors were
invalid, the entire group of selectors would be invalid. This would
invalidate the rule for all three heading elements, whereas in the
former case only one of the three individual heading rules would be
invalidated.

Invalid CSS example:

h1 { font-family: sans-serif }
h2..foo { font-family: sans-serif }
h3 { font-family: sans-serif }

is not equivalent to:

h1, h2..foo, h3 { font-family: sans-serif }

because the above selector (h1, h2..foo, h3) is entirely invalid and
the entire style rule is dropped. (When the selectors are not grouped,
only the rule for h2..foo is dropped.)


CSS 2 didn't specify what to do when one selector was wrong. In fact the W3C spec states that the condensed form is equivalent to the written out version:

In this example, we condense three rules with identical declarations
into one. Thus,

h1 { font-family: sans-serif }
h2 { font-family: sans-serif }
h3 { font-family: sans-serif }

is equivalent to:

h1, h2, h3 { font-family: sans-serif }

EDIT: (thx @BoltClock):

CSS 2.1 does specify the behavior and it is the same as with CSS3:

(...) since the "&" is not a valid token in a CSS 2.1 selector, a CSS 2.1 user agent must ignore the whole second line.



Related Topics



Leave a reply



Submit