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
selectorsA 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
Never use !important on site-wide css.
Only use !important on
page-specific css that overrides site-wide or foreign css (from ExtJs
or YUI for example).Never use !important when you're writing a
plugin/mashup.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
Bootstrap Navbar Collapse Media-Query on Custom Width
How to Use Google Web Fonts in an HTML Email
Why Are My Descenders Being Cut Off When Using CSS @Font-Face
Why Are Inline-Block Elements Not Displayed Correctly in Internet Explorer 8
What's the Difference Between a Block-Level Box and a Principal Block-Level Box
How to Append a Stylesheet to <Head> in Angularjs $Routeprovider
How to Prevent :After Pseudo Element from Being Read by Screen Readers
Tweaking Bootstrap 2.0 for Semantic Markup
Offset Scroll Anchor in HTML with Bootstrap 4 Fixed Navbar
Svg "Fill: Url(#....)" Behaving Strangely in Firefox
CSS Percentage Width and Text-Overflow in a Table Cell
iOS CSS Opacity + Visibility Transition
Add Prefixes to CSS Class Names Using Less or SASS
Calculating Viewport Height on Chrome Android with CSS
CSS Transition Not Working for Percentage Height
Structuring CSS (Sass, Less) Files by Elements, by Function and by Media Queries: 3D Code Structure