虛擬類別選擇器 ( 邏輯判斷 )
這篇教學會介紹「邏輯判斷」虛擬類別選擇器,這個選擇器主要有 :not()、:is() 和 :has() 三種,透過邏輯判斷的規則,就能從複雜的結構中挑選出符合規律的元素,是一種非常強大的 CSS 選擇器。
「邏輯判斷」虛擬類別選擇器
下方列出和「邏輯判斷」有關的虛擬類別選擇器 ( 支援度 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 結構,非常推薦立刻開始使用喔!
意見回饋
如果有任何建議或問題,可傳送「意見表單」給我,謝謝~