一、前言
在傳統的 CSS 中,我們只能根據元素的自身屬性、類名、ID 或其子元素/兄弟元素來設置樣式,卻無法根據其父元素或后代元素的狀態來改變自身樣式。
直到 :has()
選擇器的出現,這一局面被徹底改變。
:has()
被稱為 “父選擇器” 或 “容器選擇器”,是 CSS 選擇器的一次革命性升級。它不僅讓 CSS 擁有了更強的表達能力,還為 容器查詢(Container Queries) 提供了重要支持。
本文將深入解析 :has()
的語法、用法與實戰場景,帶你掌握這一現代 CSS 強大特性。
二、什么是 :has() 選擇器?
:has()
是一個 關系偽類選擇器(Relational Pseudo-class),用于匹配包含特定后代元素的父元素。
? 語法:
parent:has(descendant)?{/*?樣式規則?*/
}
🔍 簡單理解:
“選擇那些 包含 某個特定后代元素的父元素”。
三、基本語法與示例
1. 基礎用法:匹配包含特定子元素的父級
<div?class="card"><h3>標題</h3><p>這是一段描述文字。</p>
</div><div?class="card"><h3>標題</h3><!--?沒有?p?元素?-->
</div>
/*?只有包含?<p>?的?.card?才有邊框陰影?*/
.card:has(p)?{box-shadow:?0?4px?6px?rgba(0,0,0,0.1);border-radius:?8px;
}
2. 支持復雜選擇器
/*?包含?.error?類的表單?*/
.form:has(.error)?{border:?2px?solid?#e74c3c;
}/*?包含圖片的段落,增加行高?*/
p:has(img)?{line-height:?1.8;
}/*?包含至少兩個子項的列表?*/
ul:has(li:nth-child(2))?{background:?#f8f9fa;
}
四、為什么說 :has() 是“父選擇器”?
在 CSS 歷史上,一直無法直接選擇“父元素”。例如:
“如何選中包含
<input type="text">
的<label>
?”
過去只能通過 JavaScript 或調整 HTML 結構解決。
現在,:has()
讓 CSS 原生支持“向上選擇”:
<label>用戶名:<input?type="text"?name="username">
</label>
/*?選中包含?text?input?的?label?*/
label:has(input[type="text"])?{font-weight:?bold;color:?#333;
}
? 這就是所謂的“父選擇器”能力。
五、實戰場景:真正的“容器查詢”(Container Queries)
CSS 容器查詢(@container
)允許組件根據其容器大小而非視口大小來響應。:has()
可與之結合,實現更智能的布局。
示例:卡片根據內容動態調整
<div?class="container"?style="width:?300px;"><article?class="card"><img?src="image.jpg"?alt="圖片"><h3>帶圖片的卡片</h3><p>這是一段描述。</p></article>
</div><div?class="container"?style="width:?300px;"><article?class="card"><h3>純文本卡片</h3><p>沒有圖片。</p></article>
</div>
/*?啟用容器查詢?*/
.container?{container-type:?inline-size;
}.card?{display:?grid;gap:?12px;padding:?16px;
}/*?如果卡片包含圖片,使用兩行布局?*/
.card:has(img)?{grid-template-rows:?auto?1fr;
}/*?容器查詢?+?:has():小容器中,有圖片的卡片改為單列?*/
@container?(max-width:?320px)?{.card:has(img)?{grid-template-columns:?1fr;grid-template-rows:?auto?auto?1fr;}
}
? 組件真正實現了“內容感知”與“容器感知”。
六、高級用法與技巧
1. 多條件匹配(與邏輯)
/*?同時包含?h2?和?.btn?的?header?*/
header:has(h2):has(.btn)?{padding:?2rem;background:?#e3f2fd;
}
2. 否定匹配(結合 :not())
/*?不包含圖片的卡片?*/
.card:not(:has(img))?{font-size:?1.1em;
}
3. 表格行高亮(懸停整行)
/*?當?td?被懸停時,高亮其父?tr?*/
tr:has(td:hover)?{background-color:?#f5f5f5;
}
七、瀏覽器兼容性
瀏覽器 | 支持情況 |
---|---|
Chrome | 105+ ? |
Edge | 105+ ? |
Safari | 15.4+ ? |
Firefox | 121+ ? |
iOS Safari | 15.4+ ? |
📊 數據來源:Can I use :has()
?? 注意:目前 IE 和舊版瀏覽器不支持,生產環境建議結合漸進增強策略使用。
八、與 JavaScript 的對比
過去類似功能需 JS 實現:
document.querySelectorAll('.card').forEach(card?=>?{if?(card.querySelector('img'))?{card.classList.add('has-image');}
});
:has()
的優勢:
-
無需 JS,減少腳本依賴。
-
性能更高,由瀏覽器原生優化。
-
更簡潔,樣式邏輯集中在 CSS 中。
九、總結
:has()
選擇器是 CSS 發展史上的里程碑特性:
-
? 實現了“父選擇器”功能,打破 CSS 選擇方向限制。
-
? 與容器查詢結合,推動組件化、響應式設計進入新階段。
-
? 減少對 JavaScript 的依賴,提升樣式表達能力。
隨著瀏覽器支持度不斷提升,:has()
將成為現代前端開發的必備技能。