CSS specificity of comma-separated group selector [duplicate] - css

This question already has answers here:
Specificity rules for comma delineated lists
(4 answers)
Closed 2 years ago.
What is the proper way of computing the specificity for comma-separated group selectors?
The specificity for the following selector, for example, is 0,1,2,2 (1 for head, 1 for a, 10 for .left, 10 for :hover, and 100 for #title):
head #title .left a:hover
What would be the specificity for this selector? Would it also be 0,1,2,2? Or is this treated as multiple selectors, and a specificity has to be computed for each?
head,#title,.left,a:hover

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>
Both selectors above are targeting the same element. A class selector has more specificity than a type selector (10 v 1), so the class wins.
On the other hand, a comma-separated list of selectors applies the same rule to different elements, so specificity is not an issue.
You don't normally do this:
div, .intro {
border: 1px solid black;
}
<div class="intro">text</div>
... because it's redundant.
Comma separation is meant to consolidate selectors like this:
h1, h2, h3 {
color: red;
}
<h1>text</h1>
<h2>text</h2>
<h3>text</h3>
... which has nothing to do with specificity.

Related

Difference between the :where() and :is() pseudo-classes?

The :is() and :where() pseudo-class functions both take a selector list as an argument and select any element that can be selected by one of the selectors in that list. So how do they differ?
/* Selects any paragraph inside a header, main
or footer element that is being hovered */
:is(header, main, footer) p:hover {
color: red;
cursor: pointer;
}
/* Selects any paragraph inside a header, main
or footer element that is being hovered */
:where(header, main, footer) p:hover {
color: red;
cursor: pointer;
}
/* Both are equivalent to the following */
header p:hover,
main p:hover,
footer p:hover {
color: red;
cursor: pointer;
}
The difference between :where() and :is() is that :where() always has
0 specificity, whereas :is() takes on the specificity of the most
specific selector in its arguments.
The pseudo-class :is() doesn't have any weight itself (unlike most pseudo-classes, which are the equivalent of classes in calculating specificity), but the values inside it's parentheses are used to calculate specificity instead. (By the way, it's the same case with another pseudo-class, :not().)
Example:
div:where(.outer) p has a specificity score (ordered from highest to least specificity value: inline styling/style attribute, id, class/pseudo-class/attribute, element) of 0,0,0,2, while div:is(.outer) p is scored 0,0,1,2.
Here's a mnemonic: :is() is influential, :where() is worthless.
Source: MDN
Anything that :is() can do regarding grouping, so can :where() (including being used anywhere in the selector, nesting, and stacking them)
The difference is actually in specificity, that's the point which :is() and :where() strongly diverge.
:where() has no specificity (its specificity value is 0) and it squashes all the specificity in the selector list passed as functional parameters.
:is() takes the specificity of its most specific selector (it actually counts towards the specificity of the overall selector and takes the specificity of its most specific argument)
You can check out this great comparison : https://developer.mozilla.org/en-US/docs/Web/CSS/:where#examples

:not selector is changing the evaluated order of equivalent selectors [duplicate]

This question already has answers here:
What is the most character-efficient way to increase CSS specificity?
(4 answers)
Closed 4 years ago.
I have an issue where I'm working in a rather large CSS code base that makes frequent use of overriding previously defined classes/selectors. As such, it is very sensitive to the order in which they are defined.
Here is a sample of how I need it to work
.grid {
padding:25px;
background-color: red;
}
.grid {
padding:50px;
background-color: green;
}
<li>
<div class="grid">
Test
</div>
</li>
Notice how the second .grid definition overrides the first.
This is what is happening now:
.grid:not(.ui) {
padding:25px;
background-color: red;
}
.grid {
padding:50px;
background-color: green;
}
<li>
<div class="grid">
Test
</div>
</li>
Using the :not pseudo-class hover moves the evaluated priority to after normal class definitions. I need it to be evaluated in the same order as before, but I need the :not selector. Are there any solutions besides refactoring?
The :not rule is more specific, so it takes higher precedence.
If you can't refactor, you could put a bogus :not condition on the other rule as well, so they'll have the same precedence and thus revert to document order:
.grid:not(.ui) {
padding:25px;
background-color: red;
}
.grid:not(.nonexistentclassname) {
padding:50px;
background-color: green;
}
<li>
<div class="grid">
Test
</div>
</li>
You just need to make the selector you want to take precedence be more specific than the other one. If you add a "dummy" class to the element, you can add that class to your second selector to make it more specific (or at least make a tie where then, the last selector wins).
CSS Specificity is calculated as follows:
1000 points for an inline style
100 points for an id in the selector
10 points for a class or pseudo-class in the selector
1 point for an element or pseudo-element in the selector
In your case:
.grid:not(.ui)
Is worth 20 points because the selector has 1 class and one pseudo-classes in it.
But:
.grid
is only worth 10 points because of the one class.
/* This selector is worth 20 points */
.grid:not(.ui) {
padding:25px;
background-color: red;
}
/* This selector is also worth 20 points, but becomes it comes
after the other one, the location breaks the tie. */
.grid.special {
padding:50px;
background-color: green;
}
<li>
<!-- Adding another "dummy" class to the element allows you
to correctly find it with your CSS, and do it with a more
specific selector, if needed. -->
<div class="grid special">
Test
</div>
</li>
And, what if you need (for some reason) have the order of the selectors reversed? Just make the one that is suppose to "win" a little more specific:
/* This selector is worth 21 points */
div.grid.special {
padding:50px;
background-color: green;
}
/* This selector is worth 20 points */
.grid:not(.ui) {
padding:25px;
background-color: red;
}
<li>
<!-- Adding another "dummy" class to the element allows you
to correctly find it with your CSS, and do it with a more
specific selector, if needed. -->
<div class="grid special">
Test
</div>
</li>
Here's a great site for understanding how specificity is calculated that let's you "play" with selectors.
In your first example the .grid selectors each have a specificity value of 10 (classes = 10). Therefore, since both rules have the same specificity, their source order decides.
In your second rule, .grid:not(.ui) has a specificity value of 20 (2 classses; the :not() pseudo-class has no specificity value). The source order is subordinate because the rules have different specificity values.
So, to achieve your goal (the same behavior as before but with :not() applied to the first rule), you need to boost the specificity of the second rule by at least 10.
One method would be to add a useless :not() to the second rule. This method is described in another answer and is allowed by the spec:
6.6.7. The negation
pseudo-class
Note: the :not() pseudo allows useless selectors to be written. For
instance :not(*|*), which represents no element at all, or
foo:not(bar), which is equivalent to foo but with a higher
specificity.
.grid:not(.ui) {
padding:25px;
background-color: red;
}
.grid:not(.bar) {
padding:50px;
background-color: green;
}
<div class="grid">Test</div>
specificity calculator

Negative selecting without direct path in CSS [duplicate]

This question already has answers here:
CSS negation pseudo-class :not() for parent/ancestor elements
(2 answers)
Closed 5 years ago.
I want the following selector to match only those <span> elements that are direct children of '.grand-grand-child' and not descendants of '.grand-grand-parent':
:not(.grand-grand-parent) .grand-grand-child > span {
color: blue;
}
But it fails to apply the rule. Is it possible to solve the problem without Javascript? In my experience, :not rules at the beginning have to be followed with direct path made with > signs. Am I right?
See, there's a problem here: the first part of this selector will be applied to any element in the second selector's match ancestor chain (in attempt to match the whole rule). Consider the following:
:not(.parent) .child {
color: blue;
}
<div class="parent">
<div class="child">
Which color am I?
</div>
</div>
And the answer is blue, even though that .child element is clearly matched by .parent .child rule. The problem is, this rule reads as
match any element with class 'child' if one of its ancestors is without class 'parent'
And of course, it has such an ancestor - <body> element. Now compare with this fragment:
:not(.parent) > .child {
color: blue;
}
<div class="parent">
<div class="child">
Which color am I?
</div>
</div>
And now the answer is black, as the selector reads as...
match any element with class 'child' if its direct parent is without class 'parent'
Another way will be opened when browsers start supporting CSS Selectors Level 4 negation spec, allowing something more than simple selector as :not argument. It'll be possible to write something like:
.child:not(.parent *) { /* */ }
And now if any element is ancestor chain of .child matches .parent, it's not matched. But both Chrome and Firefox at the moment of writing still lack support of this feature - they only support CSS Level 3 negation.

What's the difference between p ::first-letter and p::first-letter? [duplicate]

This question already has answers here:
What does a space mean in a CSS selector? i.e. What is the difference between .classA.classB and .classA .classB? [duplicate]
(3 answers)
Closed 6 years ago.
What's the difference between p ::first-letter and p::first-letter?
p::first-letter can successfully select the first letter inside a paragraph, but p ::first-letter cannot.
The selector p::first-letter selects the first letter inside the p whereas the p ::first-letter selects the first letter within the child elements of the p.
p ::first-letter is equivalent to p *::first-letter. The below is what the specs say:
If a universal selector represented by * (i.e. without a namespace prefix) is not the only component of a sequence of simple selectors selectors or is immediately followed by a pseudo-element, then the * may be omitted and the universal selector's presence implied.
Note: Even though the selector (p ::first-letter) itself points to the first letter inside all child elements, the ::first-letter selector works only on block or inline-block elements and hence wouldn't work on a span unless its display is modified.
p ::first-letter {
color: red;
}
p::first-letter {
color: blue;
}
span{
display: inline-block;
}
<p>Some text <span>inside a span</span> and <span>inside this span too</span>
</p>
p ::first-letter means change the style of the first letter of any element which is a descendant of p. Whereas p::first-letter means change the first letter of the p element.

What does the dot mean in CSS?

Can someone explain the difference for these two CSS selectors?
.work-container . h3 {
font-size: 14px;
margin-top: 0px;
font-weight: 600;
height: 27px;
}
What is the extra dot in the upper definition?
.work-container h3 {
font-size: 14px;
margin-top: 0px;
font-weight: 600;
height: 27px;
}
Cases
Selector start with dot
.class_name signifies class name
Two dotted selector separated by space
.outside .inside
means element with .inside class descended from an element with class .outside
Two dotted selector without separation
.name1.name2
means element that has both class name1 and name2
eg: class="name1 name2"
Related questions:
What does a space mean in a CSS selector? i.e. What is the difference between .classA.classB and .classA .classB?
What's the difference between CSS classes .foo.bar (without space) and .foo .bar (with space)
A . prefix usually represents a class selector, but if it's immediately followed by whitespace then it's a syntax error.
If I were to hazard a guess, then it's likely the author meant to say .work-container > h3, but missed the Shift key just as he was about to type the > character (the child combinator).
Your second selector, .work-container h3, simply means any h3 that's contained within an element with a class called work-container.
. in CSS means it is a class and it can be applied to many elements.
# in CSS means it is an ID and it can be applied to one element per page.
Without the either, it is a tag, targets all the elements with the tag name.
In your syntax, .work-container . h3 is actually error. The . should have been either , or as BoltClock said, >, which says the direct descendant operator in CSS.
. says its class
# means its an id
and if there is nothing but the selector, then it is a tag
. in CSS means it is a class & it can be applied to many elements with use space between classes
For example:
<h3 class="class1 class2 class2">Heading</h3>
# in CSS means it is an ID and it can be applied to one element per page.
For example
<h3 id="idname1">Heading</h3>

Resources