在 CSS 編寫中,你是否遇到過這樣的場景:需要給多個不同父元素下的子元素設置相同樣式,結果寫出一長串重復的選擇器?比如給header
、main
、footer
中的p
標簽設置相同的顏色,傳統寫法可能是header p, main p, footer p { color: #333; }
。這樣的代碼不僅冗長,還容易出錯。而 CSS 新增的:is()
和:where()
偽類,就像兩把 “簡化神器”,能將復雜的選擇器合并成簡潔的形式,讓代碼更易讀、易維護。今天,我們就來解鎖這兩個提升 CSS 效率的 “語法糖”。
一、認識 :is () 與 :where ():選擇器的 “合并工具”
:is()
和:where()
都是 CSS Selectors Level 4 規范中引入的偽類,它們的核心功能相同:接收一個選擇器列表作為參數,匹配列表中任意一個選擇器能匹配的元素。簡單說,就是將多個選擇器 “合并” 成一個,避免重復書寫。
1.1 基礎語法:化繁為簡的選擇邏輯
/* 傳統寫法:多個選擇器重復部分 */
header h1,
header h2,
header h3 {color: #222;
}/* :is() 簡化寫法 */
header :is(h1, h2, h3) {color: #222;
}/* :where() 簡化寫法 */
header :where(h1, h2, h3) {color: #222;
}
可以看到,:is(h1, h2, h3)
等價于h1, h2, h3
,但與前面的header
結合后,代碼從三行精簡為一行,且避免了重復書寫header
。
1.2 解決的核心問題:減少選擇器冗余
在復雜布局中,選擇器可能包含多層嵌套,此時:is()
和:where()
的優勢更加明顯:
/* 傳統寫法:冗長且重復 */
section .title,
article .title,
aside .title,
nav .title {font-weight: bold;margin-bottom: 1rem;
}/* 簡化寫法:用 :is() 合并父元素 */
:is(section, article, aside, nav) .title {font-weight: bold;margin-bottom: 1rem;
}
這種簡化不僅讓代碼更短,還降低了修改成本 —— 如果需要添加或移除一個父元素(如footer
),只需在:is()
的參數中操作一次,無需修改多個選擇器。
二、:is () 與 :where () 的核心區別:優先級不同
:is()
和:where()
的功能幾乎完全相同,但有一個關鍵區別:優先級計算方式不同。
-
:is()
:它的優先級等于參數列表中優先級最高的選擇器的優先級。 -
:where()
:它的優先級始終為0(最低優先級),不會影響整體選擇器的優先級。
2.1 優先級對比示例
/* 基礎樣式 */
.text {color: black;
}/* :where() 選擇器:優先級 0 */
:where(.container) .text {color: blue;
}/* :is() 選擇器:優先級由 .container 決定(10) */
:is(.container) .text {color: red;
}
<div class="container"><p class="text">這段文字是什么顏色?</p>
</div>
結果:文字最終為紅色。原因是:
-
:where(.container) .text
的優先級是0 + 10
(.text
的優先級)= 10。 -
:is(.container) .text
的優先級是10
(.container
的優先級) +10
(.text
的優先級)= 20,高于前者。 -
因此
:is()
的樣式會覆蓋:where()
的樣式。
2.2 優先級應用場景
-
需要保持低優先級時,用
:where()
:比如通用組件庫的樣式,希望用戶能輕松覆蓋。 -
需要繼承高優先級時,用
:is()
:比如項目中的特定樣式,不希望被輕易覆蓋。
/* 組件庫樣式:用 :where() 確保低優先級,方便用戶覆蓋 */
:where(.btn) {padding: 0.5rem 1rem;border: none;
}/* 項目樣式:用 .btn 即可覆蓋(優先級 10 > 0) */
.btn {padding: 0.6rem 1.2rem;
}
三、進階用法:嵌套與復雜選擇器處理
:is()
和:where()
支持嵌套,還能處理包含組合選擇器(如后代、子元素、相鄰兄弟等)的場景,進一步簡化代碼。
3.1 嵌套使用:多層選擇器合并
/* 傳統寫法:多層嵌套的重復選擇器 */
header nav ul li a,
header nav ul li span,
footer nav ul li a,
footer nav ul li span {color: #666;
}/* 簡化寫法:嵌套 :is() */
:is(header, footer) nav ul li :is(a, span) {color: #666;
}
3.2 處理組合選擇器:后代、子元素、偽類等
/* 傳統寫法:多個偽類選擇器 */
.card:hover .title,
.card:focus-within .title,
.card:active .title {transform: scale(1.05);
}/* 簡化寫法:用 :is() 合并偽類 */
.card:is(:hover, :focus-within, :active) .title {transform: scale(1.05);
}
3.3 配合否定偽類 :not () 使用
:is()
和:where()
可以與:not()
結合,實現更靈活的排除邏輯:
/* 選擇除了 h1、h2 之外的標題元素 */
:is(h1, h2, h3, h4, h5, h6):not(:is(h1, h2)) {font-size: 1.2rem;
}/* 等價于 */
h3,
h4,
h5,
h6 {font-size: 1.2rem;
}
四、實戰案例:讓 CSS 代碼更簡潔
4.1 響應式布局:簡化媒體查詢中的選擇器
在響應式布局中,不同斷點下可能需要給多個元素設置相同樣式,:is()
可以減少重復:
/* 傳統寫法:斷點中重復的選擇器 */
@media (max-width: 768px) {header .logo,header .nav,footer .logo,footer .nav {flex-direction: column;}
}/* 簡化寫法:用 :is() 合并 */
@media (max-width: 768px) {:is(header, footer) :is(.logo, .nav) {flex-direction: column;}
}
4.2 通用樣式重置:用 :where () 降低優先級
在樣式重置(Reset CSS)中,使用:where()
可以確保重置樣式的優先級最低,方便后續覆蓋:
/* 傳統重置:優先級可能過高,難以覆蓋 */
ul,
ol,
menu {margin: 0;padding: 0;list-style: none;
}/* 用 :where() 重置:優先級 0,易覆蓋 */
:where(ul, ol, menu) {margin: 0;padding: 0;list-style: none;
}/* 后續樣式可以輕松覆蓋(優先級 10 > 0) */
.custom-list {margin: 1rem 0;list-style: disc;
}
4.3 組件樣式:用 :is () 統一處理多種狀態
在組件設計中,一個組件可能有多種狀態(如默認、禁用、加載中),:is()
可以合并這些狀態的選擇器:
/* 按鈕組件的多種狀態樣式 */
.btn:is(:disabled, .loading) {opacity: 0.7;cursor: not-allowed;pointer-events: none;
}/* 等價于 */
.btn:disabled,
.btn.loading {opacity: 0.7;cursor: not-allowed;pointer-events: none;
}
五、避坑指南:使用時的注意事項
5.1 瀏覽器兼容性
:is()
和:where()
兼容所有現代瀏覽器(Chrome 88+、Firefox 78+、Safari 14+、Edge 88+),但需要注意:
-
早期瀏覽器可能需要帶前綴的版本(如
:-webkit-any()
和:-moz-any()
),但現在已基本淘汰。 -
IE 完全不支持,如需兼容 IE,需避免使用或通過 PostCSS 等工具轉譯。
5.2 避免選擇器范圍過大
:is()
和:where()
會匹配參數列表中的所有選擇器,若范圍過大可能導致意外匹配:
/* 問題:會匹配所有 div 中的 p,包括嵌套在其他元素中的 div */
:is(div) p {color: red;
}/* 優化:明確父元素范圍 */
.container:is(div) p {color: red;
}
5.3 注意優先級陷阱
:is()
的優先級由參數中優先級最高的選擇器決定,可能導致樣式覆蓋不符合預期:
/* :is() 的優先級由 #id 決定(100) */
:is(.class, #id) p {color: blue;
}/* 這個選擇器的優先級是 10(.class)+ 10(p)= 20,會被上面覆蓋 */
.class p {color: red;
}
解決方法:了解:is()
的優先級計算規則,必要時用更具體的選擇器覆蓋。
六、總結
:is()
和:where()
作為 CSS 中的 “語法糖”,雖然沒有引入新的功能,但顯著提升了代碼的簡潔性和可維護性。它們的核心價值在于:
-
簡化代碼:將重復的選擇器合并,減少冗余,讓 CSS 更易讀。
-
降低維護成本:修改選擇器時只需操作一次,避免遺漏。
-
靈活控制優先級:
:where()
的低優先級適合通用樣式,:is()
的動態優先級適合特定樣式。
在實際開發中,建議:
-
寫通用組件庫或樣式重置時,優先用
:where()
,方便用戶覆蓋。 -
寫項目特定樣式時,根據優先級需求選擇
:is()
或:where()
。 -
處理多層嵌套或多狀態選擇器時,用它們合并重復部分,提升代碼質量。
如果你還在為冗長的 CSS 選擇器煩惱,不妨試試:is()
和:where()
—— 這兩個小小的 “語法糖”,可能會讓你的 CSS 代碼變得清爽許多。
你在項目中用過:is()
或:where()
嗎?歡迎在評論區分享你的使用心得~