前端開發

CSS :is() 是什麼?讓選擇器更簡潔的實用語法

CSS :is() 是什麼?讓選擇器更簡潔的實用語法

CSS :is() 是什麼?讓選擇器更簡潔的實用語法

在寫 CSS 時,我們常常會遇到多個 selector 需要套用同一組樣式的情境。

如果每個 selector 都分開寫,CSS 很容易變得冗長、重複,也不太好維護。

這時候就可以使用 CSS 的 :is() 選擇器函式。


:is() 是什麼?

:is() 是 CSS 的一種 選擇器函式,可以把多個 selector 條件合併在一起。

它的意思可以理解成:

只要符合括號裡任一個 selector,就套用這段 CSS。

例如:

:is(h1, h2, h3) {
  color: red;
}

代表 h1h2h3 都會套用這組樣式。


基本範例

原本我們可能會這樣寫:

.card h1,
.card h2,
.card h3 {
  color: red;
}

使用 :is() 後,可以改成:

.card :is(h1, h2, h3) {
  color: red;
}

這段 CSS 的意思是:

.card 裡面的 h1、h2、h3 都套用 color: red

也就是說,:is(h1, h2, h3) 代表:

h1 或 h2 或 h3

要注意空格的位置

在使用 :is() 時,要注意 selector 中間有沒有空格,因為意思會不一樣。

有空格

.card :is(h1, h2, h3) {
  color: red;
}

代表:

.card 裡面的 h1、h2、h3

也就是選取 .card 內部的標題元素。


沒有空格

.card:is(h1, h2, h3) {
  color: red;
}

代表:

同一個元素本身同時有 .card,且它本身是 h1、h2 或 h3

例如下面這種元素才會被選到:

<h1 class="card">Title</h1>

所以:

.card :is(h1, h2, h3)

和:

.card:is(h1, h2, h3)

意思是不一樣的。


為什麼要使用 :is()

1. 減少重複的 selector

假設我們想讓 headermainfooter 裡面的連結都套用同樣樣式。

原本可能會寫成:

header a,
main a,
footer a {
  color: blue;
}

使用 :is() 可以簡化成:

:is(header, main, footer) a {
  color: blue;
}

這樣不只比較短,也比較容易閱讀。


2. 讓相同樣式集中管理

例如我們有兩種按鈕樣式:

.btn-primary {
  padding: 8px 16px;
  border-radius: 4px;
}

.btn-secondary {
  padding: 8px 16px;
  border-radius: 4px;
}

這兩個 class 有相同的基礎樣式,就可以使用 :is() 合併:

:is(.btn-primary, .btn-secondary) {
  padding: 8px 16px;
  border-radius: 4px;
}

這樣可以避免重複撰寫相同的 CSS。


3. 搭配文章內容排版很實用

在處理文章頁、Blog 頁、CMS 內容時,常常會針對標題、段落、清單統一設定間距。

例如:

.article :is(h2, h3, p, ul, ol) {
  margin-bottom: 16px;
}

代表:

.article 裡面的 h2、h3、p、ul、ol 都會有 margin-bottom: 16px

這種寫法很適合用在文章內容排版,因為可以減少大量重複的 selector。


4. 搭配狀態選擇器使用

:is() 也可以搭配 :hover:focus 這類狀態 selector。

例如:

button:is(:hover, :focus) {
  background: black;
  color: white;
}

這段的意思是:

button 在 hover 或 focus 狀態時,都套用這組樣式

如果不用 :is(),可能會寫成:

button:hover,
button:focus {
  background: black;
  color: white;
}

使用 :is() 後可以讓狀態條件更集中。


:is():where() 的差別

:is():where() 看起來很像,都是用來合併 selector。

例如:

:is(.card, #main) p {
  color: red;
}

以及:

:where(.card, #main) p {
  color: red;
}

兩者最大的差別在於 CSS 權重,也就是 specificity


:is() 會採用括號內最高的權重

:is() 本身不會額外增加權重,但它會採用括號內 selector 中 權重最高的那一個

例如:

:is(.card, #main) p {
  color: red;
}

因為 #main 是 id selector,權重比 .card 高,所以 :is(.card, #main) 這一段會採用 #main 的權重。

也就是說,這段 selector 的權重會比較高,後續如果想覆蓋樣式,就需要注意 specificity 的影響。


:where() 權重永遠是 0

:where() 的特點是:

本身權重永遠是 0

例如:

:where(.card, #main) p {
  color: red;
}

即使括號裡有 .card#main:where() 也不會增加權重。

所以 :where() 很適合用在「預設樣式」、「基礎樣式」、「容易被覆蓋的樣式」。


簡單比較

語法 用途 權重
:is() 合併多個 selector 採用括號內最高權重
:where() 合併多個 selector 權重永遠是 0

簡單記法:

:is()     = 合併 selector,會採用括號內最高權重
:where()  = 合併 selector,但權重是 0,容易被覆蓋

什麼時候適合使用 :is()

適合使用 :is() 的情境包含:

1. 多個 selector 要套用同一組樣式
2. 想減少 CSS 重複撰寫
3. 想讓巢狀 selector 更好閱讀
4. 多個狀態需要共用樣式
5. 文章頁、內容頁需要統一設定標題與段落樣式

例如:

.article :is(h1, h2, h3, p, blockquote) {
  margin-bottom: 1rem;
}

或是:

.form-control:is(:hover, :focus) {
  border-color: #333;
}

使用 :is() 要注意什麼?

雖然 :is() 很方便,但還是要注意權重問題。

例如:

:is(.card, #main) p {
  color: red;
}

因為裡面包含 #main,所以整段 selector 的權重會變高。

如果你的目標只是寫一組容易被覆蓋的基礎樣式,可能就比較適合使用 :where()

另外,也要注意 selector 中間有沒有空格:

.card :is(h1, h2, h3)

代表選取 .card 裡面的 h1h2h3

但:

.card:is(h1, h2, h3)

代表選取本身同時符合 .card,且是 h1h2h3 的元素。


結論

:is() 是一個可以讓 CSS selector 更簡潔、更好維護的語法。

它特別適合用在多個 selector 共用樣式的情境,例如標題、段落、按鈕、表單狀態等等。

可以把它簡單理解成:

:is() = 括號裡只要符合其中一個條件,就套用樣式

而它和 :where() 最大的差別是:

:is() 會採用括號內最高權重
:where() 權重永遠是 0

在實務上,如果你想減少重複 selector,又希望保留正常 CSS 權重,可以使用 :is()

如果你想寫容易被覆蓋的基礎樣式,則可以考慮使用 :where()


參考資料