In the CSS selector family, a relatively new selector is added–Logic selectorAt present, there are 4 members:
:is
:where
:not
:has
This article will lead you to understand and deepen them. Make learning practical and write more modern selectors.
: is pseudo class selector
:is()
The CSS pseudo class function takes the selector list as a parameter and selects the elements that can be selected by any selector in the list.
Previously, for some common style settings of the same child element of multiple different parent containers, the following CSS code may appear:
header p:hover,
main p:hover,
footer p:hover {
color: red;
cursor: pointer;
}
And now there is:is()
Pseudo class, the above code can be rewritten as:
:is(header, main, footer) p:hover {
color: red;
cursor: pointer;
}
It does not implement a new function of a selector, but is more like a syntax sugar, which is similar to the class () syntax in JavaScript ES6. It only repackages the original function, realizes the syntax of expressing an operation more easily, and simplifies the writing of some complex code.
Grammatical sugar(synchronous sugar) refers to the syntax that can more easily express an operation in a programming language. It can make it easier for programmers to use the language, and the operation can become clearer and more convenient, or more in line with the programming habits of programmers. To understand in a more understandable way is to change a writing method on the basis of a previous grammar. The functions are the same, but the writing method is different, mainly to make it easier for developers to understand in the process of use.
Yitusheng foreword (quoted toNew CSS functional pseudo-class selectors :is() and :where()):
Support multi-layer stacking and continuous use
Take another look at this situation. The original CSS code is as follows:
<div><i>div i</i></div>
<p><i>p i</i></p>
<div><span>div span</span></div>
<p><span>p span</span></p>
<h1><span>h1 span</span></h1>
<h1><i>h1 i</i></h1>
If you want to add the above HTML,<div>
and<p>
Down<span>
and<i>
The color of CSS is set to red. Normal CSS may be as follows:
div span,
div i,
p span,
p i {
color: red;
}
Yes:is()
After, the code can be simplified as:
:is(div, p) :is(span, i) {
color: red;
}
The results are as follows:
Here, it also supports:is()
For cascading. adopt:is(div, p) :is(span, i)
The above four rows of selectors can be combined to achieve the same effect.
Of course, this example is relatively simple. I can’t see it:is()
The power of. The following example is obvious, such a large section of CSS selector code:
ol ol ul, ol ul ul, ol menu ul, ol dir ul,
ol ol menu, ol ul menu, ol menu menu, ol dir menu,
ol ol dir, ol ul dir, ol menu dir, ol dir dir,
ul ol ul, ul ul ul, ul menu ul, ul dir ul,
ul ol menu, ul ul menu, ul menu menu, ul dir menu,
ul ol dir, ul ul dir, ul menu dir, ul dir dir,
menu ol ul, menu ul ul, menu menu ul, menu dir ul,
menu ol menu, menu ul menu, menu menu menu, menu dir menu,
menu ol dir, menu ul dir, menu menu dir, menu dir dir,
dir ol ul, dir ul ul, dir menu ul, dir dir ul,
dir ol menu, dir ul menu, dir menu menu, dir dir menu,
dir ol dir, dir ul dir, dir menu dir, dir dir dir {
list-style-type: square;
}
Available:is()
Optimized as:
:is(ol, ul, menu, dir) :is(ol, ul, menu, dir) :is(ul, menu, dir) {
list-style-type: square;
}
Pseudo elements are not supported
There is a special case that cannot be used:is()
To select::before
and::after
Two pseudo elements. For example:
Note that only pseudo elements and pseudo classes are not supported, such as
:focus
、:hover
Yes.
div p::before,
div p::after {
content: "";
//...
}
Cannot be written as:
div p:is(::before, ::after) {
content: "";
//...
}
:is
Priority of selector
Look at such an interesting situation:
<div>
<p class="test-class" id="test-id">where & is test</p>
</div>
<div>
<p class="test-class">where & is test</p>
</div>
We bring.test-class
Element, set a default color:
div .test-class {
color: red;
}
If, at this time, we introduce:is()
Match:
div :is(p) {
color: blue;
}
At this time, due todiv :is(p)
Can be seen asdiv p
, priority is nodiv .test-class
High, therefore, the color of the selected text will not change.
But if we are:is()
In the selector, add one#test-id
, the situation is different.
div :is(p, #text-id) {
color: blue;
}
It is understood that if the above selector is split, the above code can be split into:
div p {
color: blue;
}
div #text-id {
color: blue;
}
Well, we have reason to guess that with#text-id
of<p>
With a higher priority selector, the color of the element will becomeblue
, and the other onediv p
Because the priority is not high enough, the first paragraph of the text is stillgreen
。
But here, miraculously, both texts becomeblue
:
CodePen Demo — the specificity of CSS :is selector
This is because,:is()
The priority of is determined by the selector with the highest priority in its selector list. We can’t cut them apart.
aboutdiv :is(p, #text-id)
,is:()
There is an ID selector inside, so all elements matched by this rule will be applieddiv #id
Selector priority at this level. This is very important. Again, for:is()
We can’t separate the priorities of selectors. They are a whole, and the priority depends onThe selector with the highest priority in the selector list。
Alias of: is: matches() and: any()
:is()
It is the latest standard naming. Before, there have been choices with the same function, which are:
:is(div, p) span {}
//Equivalent to
:-webkit-any(div, p) span {}
:-moz-any(div, p) span {}
:matches(div, p) span {}
Of course, the following three have been abandoned, and it is not recommended to continue to use them. And today (2022-04-27):is()
The compatibility of is already very good. If you don’t need to be compatible with IE series, you can consider starting to use it (cooperate withautoprefixer
), lookCanIUse:
: where pseudo class selector
Got it:is
After that, we can have a look again:where
, the two of them have a very strong correlation.:where
It also takes the selector list as its parameter and selects any element that can be selected by one of the selectors in the list.
Another example:
:where(header, main, footer) p:hover {
color: red;
cursor: pointer;
}
The above code uses:where
, which can be roughly seen as:
header p:hover,
main p:hover,
footer p:hover {
color: red;
cursor: pointer;
}
That’s interesting. It’s not the same as above:is
Is it the same?
So what is the difference between them?
:is
and:where
Differences between
First, grammatically,:is
and:where
It’s exactly the same. Their core difference ispriority。
Take an example:
<div>
<p>where & is test</p>
</div>
CSS code is as follows:
:is(div) p {
color: red;
}
:where(div) p {
color: green;
}
Normally, according to our understanding,:is(div) p
and:where(div) p
Can be converted intodiv p
, because:where(div) p
After definition, so the color of the text should begreen
Green, however, the actual color iscolor: red
Red:
This is because,:where()
and:is()
The difference is that,:where()
Priority ofAlways 0, but:is()
The priority of is determined by the selector with the highest priority in its selector list.
The above example is not particularly obvious. Let’s make a slight Transformation:
<div id="container">
<p>where & is test</p>
</div>
We add an ID attribute to div and modify the above CSS code:
:is(div) p {
color: red;
}
:where(#container) p {
color: green;
}
Even so, because:where(#container)
The priority of is 0, so the color of the text is still red.:where()
Priority ofAlways 0This point needs to be kept in mind in the process of use.
Combination, nesting
A very big feature of CSS selectors is composition and nesting.:is
and:where
It is no exception. Therefore, they can also be combined and nested with each other. The following CSS selectors are reasonable:
/*Combination*/
:is(h1,h2) :where(.test-a, .test-b) {
text-transform: uppercase;
}
/*Nesting*/
.title:where(h1, h2, :is(.header, .footer)) {
font-weight: bold;
}
Here is a brief summary,:is
and:where
Are very good grouping logic selectors, the only difference is:where()
Priority ofAlways 0, and:is()
The priority of is determined by the selector with the highest priority in its selector list.
: not pseudo class selector
Now let’s introduce some very useful:not
Pseudo class selector.
:not
Pseudo class selectors are used to match elements that do not match a set of selectors. Because its function is to prevent specific elements from being selected, it is also called negation pseudo class.
For example, the HTML structure is as follows:
<div class="a">div.a</div>
<div class="b">div.b</div>
<div class="c">div.c</div>
<div class="d">div.d</div>
div:not(.b) {
color: red;
}
div:not(.b)
It can be selected except that class is.b
All div elements except element:
MDN error example? An interesting phenomenon
Interestingly, it is introduced in MDN:not
For example:
/* Selects any element that is NOT a paragraph */
:not(p) {
color: blue;
}
intend,:not(p)
You can choose any not<p>
Element of the label. However, the CSS selector above, in the following HTML structure, the measured results are not quite right.
<p>p</p>
<div>div</div>
<span>span</span>
<h1>h1</h1>
The results are as follows:
intend,:not(p)
Can still be selected<p>
Element. I tried several browsers and got the same results.
CodePen Demo — :not pesudo demo
Why is this? This is due to:not(p)
Can also be selected<body>
, then<body>
The color of becomesblue
, becausecolor
Is an inheritable attribute,<p>
The tag inherits<body>
The color attribute of the resulting<p>
It’s also blue.
Let’s change it into a non inheritable attribute and try it:
/* Selects any element that is NOT a paragraph */
:not(p) {
border: 1px solid;
}
OK, this time<p>
No border reflection, no problem! When actually using, you need to pay attention to the inheritance of this layer!
: priority issues for not
Here are some uses:not
Problems needing attention.
:not
、:is
、:where
Unlike other pseudo classes, these pseudo classes do not increase the priority of selectors. Its priority is the priority of its parameter selector.
And, inCSS Selectors Level 3,:not()
Only a single selector is supported in, and fromCSS Selectors Level 4Start,:not()
Multiple selectors are supported internally, such as:
/*CSS selectors Level 3,: Notif there are multiple values inside, they need to be separated*/
p:not(:first-of-type):not(.special) {
}
/*CSS selectors level 4 supports comma separation*/
p:not(:first-of-type, .special) {
}
And:is()
similar,:not()
The selector itself does not affect the priority of the selector, which is determined by the selector with the highest priority in its selector list.
: not (*) problem
use:not(*)
Will match any non element element, so this rule will never be applied.
It’s equivalent to a meaningless piece of code.
: not() cannot be nested: not()
No dolls.:not
Pseudo classes are not allowed to be nested, which means:not(:not(...))
Is invalid.
: not() actual combat analysis
So, what are the particularly interesting application scenarios of: not()? Let me list one here.
stayW3 CSS selectors-4 specificationIn, a very interesting new one is added:focus-visible
Pseudo class.
:focus-visible
This selector can effectively display different forms of focus according to the user’s input mode (mouse vs keyboard).
With this pseudo class, it can be achieved that when the user uses the mouse to operate the focusable element, it will not be displayed:focus
Style or make it weak, and when the user uses the keyboard to operate the focus, use:focus-visible
, so that the focus elements can obtain a strong performance style.
Look at a simple demo:
<button>Test 1</button>
button:active {
background: #eee;
}
button:focus {
outline: 2px solid red;
}
Click with the mouse:
It can be seen that when clicking with the mouse, the element’s:active
Pseudo class, also triggered:focus
Pseudo class, not very beautiful. But if it is setoutline: none
It will make the experience of keyboard users very bad. Because when keyboard users use tab to try to switch focus, they willoutline: none
At a loss.
Therefore, you can use:focus-visible
Pseudo class transformation:
button:active {
background: #eee;
}
button:focus {
outline: 2px solid red;
}
button:focus:not(:focus-visible) {
outline: none;
}
To see the effect, click the button with the mouse and click the button with the keyboard to control the focus:
CodePen Demo — :focus-visible example
It can be seen that clicking with the mouse will not trigger:foucs
, only when the keyboard operates the focus element and uses tab to switch the focus,outline: 2px solid red
This code will take effect.
In this way, we not only ensure the click experience of normal users, but also ensure the focus management experience of users who cannot use the mouse, and we have made great efforts in accessibility.
It is worth noting why it is used herebutton:focus:not(:focus-visible)
It’s written in this way instead of directly:
button:focus {
outline: unset;
}
button:focus-visible {
outline: 2px solid red;
}
Explain,button:focus:not(:focus-visible)
Means,The button element triggers the focus state, and it is not triggered through focus visible, understood as supporting:focus-visible
Browser, activated by mouse:focus
In this case, no setting is requiredoutline
。
For compatibility not supported:focus-visible
Browser, when:focus-visible
When incompatible, you still need to have:focus
The existence of pseudo classes.
Therefore, with the help of:not()
Pseudo class, cleverly achieved a practical effect of the program degradation.
It’s a little windy here, so we need to understand it well.
: not compatibility
Experienced two versions of CSS selectors Level 3 and CSS selectors level 4. Today (2020-05-04), except for IE series,:not
The compatibility of has been very good:
: has pseudo class selector
OK。 Finally, the heaviest of all logic selectors:has
Here we go. The reason why it is important is that its birth fills the gap in the previous CSS selectors, which has no real core meaningParent selectorThe vacancy of.
:has
The pseudo class accepts a selector group as a parameter, which is relative to the:scopeMatch at least one element.
Take an example:
<div>
<p>div -- p</p>
</div>
<div>
<p class="g-test-has">div -- p.has</p>
</div>
<div>
<p>div -- p</p>
</div>
div:has(.g-test-has) {
border: 1px solid #000;
}
We passeddiv:has(.g-test-has)
Selector, which means that class under div is selected as.g-test-has
Div element of.
Note that the choice here is not:has()
The selector inside the package selects the element, but uses:has()
The host element of the pseudo class.
The effect is as follows:
You can see that the class under the second div is.g-test-has
So the second div is added with border.
: has () parent selector — parent element selection of nested structure
Let’s deepen our impression through a few demo.:has()
It can also be more complicated.
<div>
<span>div span</span>
</div>
<div>
<ul>
<li>
<h2><span>div ul li h2 span</span></h2>
</li>
</ul>
</div>
<div>
<h2><span>div h2 span</span></h2>
</div>
div:has(>h2>span) {
margin-left: 24px;
border: 1px solid #000;
}
Here, it is required to accurately select the div element that the direct child element under div is H2, and the direct child element under H2 has the div element of span. Note that the top level selected uses the parent element div of: has (). The results are as follows:
What is embodied here isNested structure to accurately find the corresponding parent element。
: has () parent selector — sibling element selection of sibling structure
There is another case, which was also difficult to deal with before, that is, the sibling element selection of peer structure.
Look at this demo:
<div class="has-test">div + p</div>
<p>p</p>
<div class="has-test">div + h1</div>
<h1>h1</h1>
<div class="has-test">div + h2</div>
<h2>h2</h2>
<div class="has-test">div + ul</div>
<ul>ul</ul>
We want to find the hierarchical relationship between brothers, followed by<h2>
Elemental.has-test
Element, which can be written as follows:
.has-test:has(+ h2) {
margin-left: 24px;
border: 1px solid #000;
}
The effect is as follows:
What is embodied here isSibling structure, accurately find the corresponding pre sibling element。
In this way, CSS has not implemented the parent selector for a long time:has()
At the beginning, it can be done. This selector can greatly improve the development experience and solve the problem that requires a lot of JavaScript code before it can be completed.
For the above demo summary, you can stamp hereCodePen Demo — :has Demo
: has() compatibility, give time
Unfortunately,:has()
In the recentSelectors Level 4It is determined in the specification that the current compatibility is still relatively poor. As of 2022-05-04, Safari and the latest version of chrome (V101) can be openedExperimental Web Platform featuresExperience)
To open this feature in chrome, 1. Enter the browser URL box chrome://flags , 2. Open \enable-experimental-web-platform-features
Wait patiently, give time, and such a good selector will soon be applied on a large scale.
last
This is the end of this article. I hope it will help you:)
If you want to get the most interesting CSS information, don’t miss my official account–ICSS front end anecdotes 😄
More wonderful CSS technical articles are summarized in myGithub — iCSS, continuous update, welcome to click star subscription collection.
If you have any questions or suggestions, you can communicate more. Original articles, limited writing style, shallow talent and learning, if there is anything wrong in the article, please let me know.