Just wondering what the difference is between CSS (selectors 4) pseudo selectors :has and :matches
The spec http://dev.w3.org/csswg/selectors-4/#overview says:
E:matches(s1, s2)
an E element that matches compound selector s1 and/or compound selector s2
§4.2 The Matches-any Pseudo-class: :matches()
E:has(rs1, rs2)
an E element, if either of the relative selectors rs1 or rs2, when evaluated with E as the :scope elements, match an element
§4.4 The Relational Pseudo-class: :has()
In a nutshell:
E:has(rs1, rs2) matches E when a different element F matches any of the selector arguments in relation to E. If you know jQuery's :has() selector, this is exactly the same thing.
E:matches(s1, s2) matches E when E itself matches any of the selector arguments. Think of :matches() as the direct opposite of :not(), which matches E if E itself does not match any of the arguments.1 You can also think of :matches() as a pseudo-class version of jQuery's .filter() method.
This notation is equivalent to concatenating every selector argument with E (provided you can actually concatenate them) such that you have a selector list (E)(s1), (E)(s2). For example, div:matches(.foo, .bar) is equivalent to div.foo, div.bar.
This fundamental difference is demonstrated most straightforwardly with the selectors div:matches(p) and div:has(p):
div:has(p) matches any div element that has a p descendant.
This is very similar to div p, except the former targets the div
and the latter targets the p.
Since a div can never be a p, div:matches(p) will never match
anything. (Likewise, div:not(p) will match all div elements.)
Here's a more complex example with slightly less absurd selectors:
div:has(.foo, .bar)
div:matches(.foo, .bar)
With the following markup:
<div class="foo"></div> <!-- [1] -->
<div class="bar"></div> <!-- [1] -->
<div class="foo bar"> <!-- [2] -->
<p></p>
</div>
<div> <!-- [3] -->
<p class="foo"></p>
</div>
<div> <!-- [3] -->
<div> <!-- [3] -->
<p class="bar"></p>
</div>
</div>
<div> <!-- [4] -->
<div class="foo"> <!-- [5] -->
<p class="bar"></p>
</div>
</div>
Which elements are matched by which selectors?
Matched by div:matches(.foo, .bar)
The first div element has the "foo" class, and the second div element has the "bar" class, so each of these satisfies its respective selector argument in the :matches() pseudo-class.
Matched by div:matches(.foo, .bar)
The third div element has both classes, so it matches both selector arguments.
A note on specificity: both of these arguments have equal specificity, making the total specificity (0, 1, 1), but when an element matches multiple selector arguments with different specificity values, the spec says that the specificity is that of the most specific argument that is matched.
Matched by div:has(.foo, .bar)
Each of these div elements has a descendant element (in this case, a p) with a class that matches its respective selector argument in the :has() pseudo-class.
Matched by div:has(.foo, .bar)
This div element has a div.foo descendant and a p.bar descendant, therefore it satisfies both relative selector arguments.
A note on specificity: because :has() is not yet in the fast profile and is therefore tentatively excluded from CSS, the concept of specificity does not apply at all. There are plans to include a limited version of this in the fast profile for use in CSS, but there is nothing concrete as yet. Any new developments will be added at an appropriate time.
Matched by div:matches(.foo, .bar) and div:has(.foo, .bar)
This div element matches both pseudo-classes:
it is .foo (as it has the "foo" class), and
it has a descendant with the "bar" class.
This element would also match div:matches(.foo, .bar):has(.foo, .bar), which would be a valid level 4 selector since a compound selector can have any combination of pseudo-classes.
Another difference between :matches() and :has() is that :has() accepts what's known as a relative selector. A relative selector has a scope; selector scoping is an entire topic in its own right, but for the purposes of :has(), the scoping element is always the element you attach the :has() pseudo-class to. But, more importantly, a relative selector can either have an implicit descendant combinator, or begin explicitly with a combinator such as >, + or ~ — this combinator is what links the rest of the relative selector to its scoping element.
For example, while :has() defaults to an ancestor-descendant relationship, you can pass a relative selector that begins with + and it then becomes an adjacent-sibling relationship: ul:has(+ p) matches any ul element that is directly followed by a p (and not necessarily one that contains a p descendant).
As for :matches(), while the overview table says that it accepts a list of compound selectors, AFAIK it hasn't yet been set in stone whether it will take a list of compound selectors or complex selectors, and in which profile (fast or complete). But a compound selector is simply the new name for what Selectors 3 currently calls a sequence of simple selectors and a complex selector is an entire series of compound selectors and combinators. A relative selector is more like a complex selector in that respect. See this answer for a non-exhaustive list of the various terms used in selectors.
1 Yes, that's "arguments" in plural — in Selectors 4, :not() can now accept a list of selectors as opposed to a single simple selector. A much-needed enhancement, but it's also to make it consistent with the other new functional pseudo-classes.
Related
In CSS, is this selector:
div:first-of-type[label="hello"]
any different from:
div[label="hello"]:first-of-type
?
Unlike pseudo element, pseudo classes can appear in the middle of a selector:
Pseudo-classes are allowed in all sequences of simple selectors contained in a selector. Pseudo-classes are allowed anywhere in sequences of simple selectors, after the leading type selector or universal selector (possibly omitted). ref
So both are the same
div[label="hello"]:first-of-type {
height:50px;
}
div:first-of-type[label="hello"] {
border:5px solid;
}
<div label="hello" class="box"></div>
Considering the new specification:
Like other simple selectors, pseudo-classes are allowed in all compound selectors contained in a selector, and must follow the type selector or universal selector, if present.
Worth to note that :first-of-type will only consider the element and its sibling. So the first selector will not select the first div having label=hello but the first div if it has the label=hello.
In other words, the 2 conditions must be true to select the element that's why the order doesn't matter and both selectors are the same.
You can see both selectors like below:
div[label="hello"]:first-of-type
(div) && (label="hello") && (first of type)
(div) && (first of type) && (label="hello")
div:first-of-type[label="hello"]
Related: Can I combine :nth-child() or :nth-of-type() with an arbitrary selector?
This is a selector used to match routerLink directive.
I know that :not(a) matches any element which is not an a element, but what does [routerLink] part mean?
In your code -- :not(a)[routerLink] -- you're saying: select all elements, except anchors, that contain the routerLink attribute.
The brackets ([]) represent an attribute selector.
<div class="somevalue">
You can target the element above like this:
[class] { background-color: red; }
It matches all elements with a class attribute.
Have a look at this table for more details:
https://www.w3.org/TR/css3-selectors/#selectors
With thanks to #BoltClock for distinguishing between two selectors that look alike, but are different:
:not(a)[routerLink]) will never match a elements
:not(a[routerLink]) will match a elements that don't have the attribute. (Note that compound selectors in the :not() pseudo-class are available as of Selectors 4.)
I am trying the :not pseudoclass selector, I want everything on the page to have color blue except the childs of a div which class="pag", so I wrote:
:not(.pag > p){
color:blue;
}
<div class="pag">
<p>First</p>
<p>Second</p>
<p>Thirt</p>
<article>Blah blah blah</article>
</div>
but it doesnt seem to work. Can somebody explain me why?
http://jsfiddle.net/Rc9pT/
It works fine if you simplify the selector:
.pag > :not(p){
color:blue;
}
JS Fiddle demo.
Albeit this 'works fine' only with the caveat that you have to specify a selector, with this approach, for every parent-child relationship; which may become burdensome.
I suspect that it's the simplicity that's required:
The negation pseudo-class, :not(X), is a functional notation taking a simple selector (excluding the negation pseudo-class itself) as an argument. It represents an element that is not represented by its argument.
A 'simple selector' is defined as:
either a type selector, universal selector, attribute selector, class selector, ID selector, or pseudo-class.
This seems to imply that any selector incorporating combinators (such as white-space, >, + or ~, among others) is not 'simple', unfortunately.
References:
Negation (:not()) pseudo-class.
Simple selector definition.
How can I make a CSS selector match all elements in the subtree of an element marked with a certain class?
I'm imagining CSS like the following (where the :subtree part is me making something up).
.diagram:subtree
{
...
}
When I write HTML like the following, the <div> and every element inside of it should be selected.
<div class="diagram">
...
</div>
Simply use the descendant selector (space):
.diagram * { … }
This selects every element beneath any element(s) that have the diagram class applied.
To match both the div itself AND its descendants, use grouping:
.diagram, .diagram * { … }
Quoting the spec:
At times, authors may want selectors to match an element that is the descendant of another element in the document tree (e.g., "Match those EM elements that are contained by an H1 element"). Descendant selectors express such a relationship in a pattern. A descendant selector is made up of two or more selectors separated by white space. A descendant selector of the form "A B" matches when an element B is an arbitrary descendant of some ancestor element A.
.diagram, .diagram *
This will select the div .diagram. The space is the descendant selector, and * is all elements.
EDIT: I thought your question originally said "including the element" hence the .diagram,, but you can simply remove that if desired.
simply use this code for it .diagram * {}
In the below example, I want to create a CSS rule that applies only to the header with the text "Blockhead".
<div class="gumby">
<span class="pokey"></span>
<h3>Blockhead</h3>
<h3>Clay rules</h3>
</div>
Can I use parentheses, such as (.gumby > .pokey) + h3? If not, what is my alternative?
No, parentheses are not valid operators in CSS selectors. They are reserved for functional notations, such as :lang(), :not(), and :nth-child().
You don't need them anyway; .gumby > .pokey + h3 by itself will work just fine.
This is because a sequence of selectors and combinators is always read linearly. Combinators don't have any sort of precedence. The selector can be interpreted as
Select an h3 element
that immediately follows an element with class pokey
that is a child of an element with class gumby.
And because of how node trees work, the use of sibling and child combinators here implies that both .pokey and the h3 are children of .gumby, which in your case they are, because of its statement that both of them are siblings.
As of 2022, we can now use the :is() selector for this purpose:
https://developer.mozilla.org/en-US/docs/Web/CSS/:is
:is(.gumby > .pokey) + h3 {
color: blue;
}
<div class="gumby">
<span class="pokey"></span>
<h3>Blockhead</h3>
<h3>Clay rules</h3>
</div>
If I understand correctly, :is() can simulate both logical AND :is(A):is(B):is(C) and logical OR :is(A, B, C), allowing for powerful combinations. Don't forget to use it in concert with other structural pseudo-classes such as :not() and :nth-child(), CSS Combinators, and DOM Traversal methods such as document.querySelectorAll().
Also, the :where() pseudo-class is identical except that it has 0 specificity, while :is() takes the specificity of its most specific argument.
h3 is not inside .pokey so you must ommit .pokey from the rule
All u'd be able to do is
.gumby h3 {}
or do this
<div class="gumby pokey">
<h3>Blockhead</h3>
<h3>Clay rules</h3>
</div>
.gumby.pokey h3 {}
if a tag has more than one class you can pile them up in css if you don't use a space character