虚拟类别选择器 ( 逻辑 )
这篇教学会介绍“逻辑判断”虚拟类别选择器,这个选择器主要有 :not()、:is() 和 :has() 三种,透过逻辑判断的规则,就能从复杂的结构中挑选出符合规律的元素,是一种非常强大的 CSS 选择器。
教学影片
搭配教学影片一起阅读,效果会更好!欢迎大家订阅 STEAM 教育学习网的 Youtube 频道。
“逻辑判断”虚拟类别选择器
下方列出和“逻辑判断”有关的虚拟类别选择器 ( 支援度 All 表示主流浏览器都支援 ):
| 虚拟类别选择器 | 说明 | 支援度 |
|---|---|---|
| :not() | 否定选择器。 | All |
| :is()、:where() | 任意比对选择器。 | IE 不支援 |
| :has() | 结构关系选择器。 | IE 不支援 |
:not()
“:not()”表示“否定选择器”,撰写方式为“:not(選擇器)”,意思是“不是这个选择器”的元素,下方的范例执行后,不是 h3 里的元素就会是红色 ( 注意因为 color 有继承特性,所以 :not() 前方要加上 body )。
<!-- HTML 程式碼 -->
<h2>oxxo</h2>
<h3>apple</h3>
<h4>banana</h4>
<h5>orange</h5>
<!-- CSS 程式碼 -->
<style>
body :not(h3) {color: red;}
</style>
通常实际使用时,会将 :not() 前方串接指定选择器,使其更有逻辑的“意义”,也能更进一步将范围缩小在指定选择器里,下方的范例执行后,所有的 class 不是 apple 的 li 元素,就会变成红色文字。
<!-- HTML 程式碼 -->
<ul>
<li>oxxo</li>
<li class="apple">apple</li>
<li>banana</li>
<li>orange</li>
</ul>
<!-- CSS 程式碼 -->
<style>
li:not(.apple) {color: red;}
</style>
:not() 支援较为复杂选择器规则,只要是“正确的选择器”,都可以被 :not 比对并且排除,下方列出一些不同的选择器规则,分别对应排除后所呈现的样式:
<!-- HTML 程式碼 -->
<ul class="g1">
<li>oxxo</li>
<li class="fruit" name="apple">apple</li>
<li class="fruit" name="banana">banana</li>
<li class="fruit">orange</li>
</ul>
<ul class="g2">
<li>oxxo</li>
<li class="fruit" name="apple">apple</li>
<li class="fruit" name="banana">banana</li>
<li class="fruit">orange</li>
</ul>
<ul class="g3">
<li>oxxo</li>
<li class="fruit" name="apple">apple</li>
<li class="fruit" name="banana">banana</li>
<li class="fruit">orange</li>
</ul>
<ul class="g4">
<li>oxxo</li>
<li class="fruit" name="apple">apple</li>
<li class="fruit" name="banana">banana</li>
<li class="fruit">orange</li>
</ul>
<!-- CSS 程式碼 -->
<style>
ul {border: 1px solid black;} /* ul 外框 */
.g1 li:not(.fruit) {background: orange;} /* 排除 class 為 fruit 的 li */
.g2 li:not(.fruit[name]) {background: pink;} /* 排除 class 為 fruit 且具有 name 屬性的 li */
.g3 li:not(.fruit:nth-child(2)) {background: green;} /* 排除 class 為 fruit 且位在第二個子元素的 li */
.g4 li:not(.fruit, [name]) {background: cyan;} /* 排除 class 為 fruit 或具有 name 屬性的 li */
</style>
:not 也支援“双重否定”的写法 ( :not(:not()) ),但这种写法比较不容易理解,且容易与“:not():not()”发生混淆,因此不建议使用!
举例来说,“:not([name]:not(.apple))”表示“选取不要有 name 属性且不要 class 不要是 fruit 的 li 元素”( 不知道在说什么 ),但“:not(li):not(.apple)”却是“不要属性 name 也不要 class 为 fruit 的 li 元素”。
<!-- HTML 程式碼 -->
<ul class="g1">
<li>oxxo</li>
<li class="fruit" name="apple">apple</li>
<li class="fruit" name="banana">banana</li>
<li class="fruit">orange</li>
</ul>
<ul class="g2">
<li>oxxo</li>
<li class="fruit" name="apple">apple</li>
<li class="fruit" name="banana">banana</li>
<li class="fruit">orange</li>
</ul>
<!-- CSS 程式碼 -->
<style>
ul {border: 1px solid black;}
.g1 li:not([name]:not(.fruit)) {background: pink;}
.g2 li:not([name]):not(.fruit) {background: orange;}
</style>
:is()、:where()
“:is()”和“:where()”表示“任意比对选择器”,意思为“指定的元素”,由于这两个虚拟类别选择器也支援较复杂的选择器语法,因此常用在“简化 CSS 程序码”,举例来说,如果有好几个父元素都对应到同样名称的子元素,就能利用 :is() 和 :where() 简化。
<!-- HTML 程式碼 -->
<ul class="g1">
<li><span>oxxo</span></li>
<li class="fruit1" name="apple"><span>apple</span></li>
<li class="fruit2" name="banana"><span>banana</span></li>
<li class="fruit3"><span>orange</span></li>
</ul>
<ul class="g2">
<li><span>oxxo</li>
<li class="fruit1" name="apple"><span>apple</span></li>
<li class="fruit2" name="banana"><span>banana</span></li>
<li class="fruit3"><span>orange</span></li>
</ul>
<!-- CSS 程式碼 -->
<style>
ul {border: 1px solid black;}
.g1 li.fruit1 span,
.g1 li.fruit2 span,
.g1 li.fruit3 span{
background: pink; /* 原本的寫法 */
}
.g2 li:is(.fruit1, .fruit2, .fruit3) span{
background: orange; /* 改用 :is(),使用 :where() 也是相同結果 */
}
</style>
虽然 :is() 和 :where() 很像,但两者差异在于“权重”,使用 :is() 后的权重等于所比对选择器的权重,而 :where() 的权重是 0,下方的范例执行后可以看到上半部使用 :is(),所以权重是 0-2-2 ( 两个 class 和两个元素 ),所以会显示样式,但使用 :where() 不会有任何权重加成,只会使用原本的 0-1-2,因此如果在排列顺序后方有相同权重的选择器,样式就会被覆盖。
<!-- HTML 程式碼 -->
<ul class="g1">
<li><span>oxxo</span></li>
<li class="fruit1" name="apple"><span>apple</span></li>
<li class="fruit2" name="banana"><span>banana</span></li>
<li class="fruit3"><span>orange</span></li>
</ul>
<ul class="g2">
<li><span>oxxo</li>
<li class="fruit1" name="apple"><span>apple</span></li>
<li class="fruit2" name="banana"><span>banana</span></li>
<li class="fruit3"><span>orange</span></li>
</ul>
<!-- CSS 程式碼 -->
<style>
ul {border: 1px solid black;}
.g1 li:is(.fruit1, .fruit2, .fruit3) span{
background: orange; /* 權重 0-2-2 */
}
.g1 li span{
background: green; /* 權重 0-1-2 */
}
.g2 li:where(.fruit1, .fruit2, .fruit3) span{
background: orange; /* 權重 0-1-2 */
}
.g2 li span{
background: green; /* 權重 0-1-2,因為擺在後面,所以會套用這個樣式 */
}
</style>
:has()
“:has()”表示“结构关系选择器”,意思为“有没有特定的子元素”,这是主流浏览器近期才支援的强大选择器,也是唯一类似“子元素选取父元素”的选择器,以下方的范例而言,如果 li 里有 span 这个子元素,这个 li 就会加上底色。
<!-- HTML 程式碼 -->
<ul class="g1">
<li>oxxo</li>
<li class="fruit1" name="apple"><span>apple</span></li>
<li class="fruit2" name="banana"><span>banana</span></li>
<li class="fruit3"><span>orange</span></li>
</ul>
<nav>
<h2>oxxo</h2>
<h3><span>hello world!!</span></h3>
<ul>
<li>grape</li>
<li>papaya</li>
<li><span>coconut</span></li>
</ul>
</nav>
<!-- CSS 程式碼 -->
<style>
li:has(span) {background: pink;} /* 如果 li 裡有 span */
</style>
小结
“逻辑判断”的虚拟类别选择器非常的强大好用!特别是近期各家浏览器都支援复杂选取器的判断后,更是能利用“逻辑判断”的方式大幅改善原本的 CSS 结构,非常推荐立刻开始使用喔!
微信扫码关注
抖音扫码关注