這個“被忽視”的 CSS4 選擇器,解決了一個折騰了十年的痛點

你是否也遇到過這種場景:想根據(jù)前一個元素來給當(dāng)前節(jié)點寫樣式,結(jié)果被 CSS 的“只能向后看”難住了? 說實話,我也卡在這兒過——而且不止一次。
今天我們用原生 CSS把這個問題一次性拿下:不用 hack、不拼接意大利面式選擇器、不借助 JavaScript。只是一個干凈利落的選擇器思路——它不只是一件工具,更像是一種更精細(xì)、更上下文驅(qū)動的樣式思維。
接下來,咱們逐步拆解:這個選擇器如何基于前一個兄弟節(jié)點精確選中目標(biāo),讓樣式既整潔,又足夠靈活。
原理一覽
主角登場::has 選擇器(在 CSS4 中引入)。它是動態(tài)樣式的“瑞士軍刀”,匹配精度高,不需要 JS,因此可維護(hù)性也更強(qiáng)。
:has 會根據(jù)元素內(nèi)部是否包含某些內(nèi)容,或其后是否緊跟/存在某些條件來決定是否命中。于是,它不僅能“向前看”(例如 “如果這個 div 里有 img 就這樣寫樣式”),也能反向利用:根據(jù)后面的內(nèi)容去影響前一個兄弟。
沒錯,我們終于有了 CSS 原生手段去實現(xiàn)這種邏輯:“如果后面出現(xiàn)了某個東西,就把前一個元素改一改?!?/span> 因此,你可以在不動 DOM 的前提下,保持結(jié)構(gòu)與表現(xiàn)的解耦。
快速示例
<h2>Heading</h2>
<p>This paragraph follows the heading</p>想要只在 h2 后面緊跟著 <p> 時修改標(biāo)題樣式?用 :has,寫法非常直接:
h2:has(+ p) {
margin-bottom: 0.25rem;
color: steelblue;
}這樣一來,只有在 h2 的緊鄰后面是段落時,標(biāo)題才會變色并收緊下邊距?!?/span>無需加工具類、無需重排 DOM。
再深入一點
:has(+ p)的語義是:如果h2的緊鄰兄弟是p,就選中這個h2。因此,它是一個條件命中器。- 關(guān)鍵在于
+:它表示緊鄰兄弟。 - 若換成
~,則表示后續(xù)任意位置的兄弟(不是必須緊鄰),從而擴(kuò)大了匹配范圍,因此更靈活也更強(qiáng)大:
h2:has(~ ul) {
border: 2px solid red;
}只要 h2 后面某處存在一個 <ul>,該標(biāo)題就會獲得一圈紅色描邊——無需添加任何額外標(biāo)記,因此在內(nèi)容編輯場景中也能自然生效,與此同時仍舊保持樣式與結(jié)構(gòu)的分離。
作用域限定
為了避免“牽一發(fā)而動全身”,把規(guī)則限制在容器內(nèi)往往是更穩(wěn)妥的做法:
.article h2:has(+ p) {
font-style: italic;
}這樣只有 .article 里的標(biāo)題會被命中,從而降低樣式外溢的風(fēng)險,并且提高可預(yù)測性。
為什么這對你重要?
你大概也厭倦了那些“補(bǔ)丁式”方案:加無意義的包裹 div、硬改 HTML 順序、甚至夾雜 JS 來兜底。 而 :has 提供的是上下文級的精度:你可以根據(jù)語義鄰接關(guān)系來寫樣式,因此布局更自適應(yīng)、然而規(guī)則仍清晰、最終維護(hù)成本更低。
真實落地的幾個用法
- 表單:只在下一個輸入是
required時高亮對應(yīng)的label。 - 卡片:當(dāng)某張卡片后面跟著某種“卡片類型”時,增加額外間距。
- 內(nèi)容排版:若標(biāo)題后緊接段落則收緊外邊距;反之如果后面是圖片,就保持較大的留白。
再看一個導(dǎo)航的例子:我們想讓當(dāng)前鏈接前一個項高亮。
<nav>
<a href="/home">Home</a>
<a href="/about" class="current">About</a>
<a href="/contact">Contact</a>
</nav>目標(biāo):當(dāng) About 處于 .current 狀態(tài)時,讓緊挨在它前面的 Home 高亮。CSS 如下:
nav a:has(+ a.current) {
color: goldenrod;
font-weight: bold;
}因為 Home恰好位于.current 的前一個兄弟位置,所以它會被高亮。因此我們無需觸碰 HTML、也不用疊加多余類名,從而保證導(dǎo)航結(jié)構(gòu)簡潔可讀。
小小“坑點”
- 功能雖強(qiáng),但也有邊界:到 2025 年,
:has在 Chrome / Firefox / Safari 15.4+ 上支持已經(jīng)很穩(wěn),不過仍建議對老舊設(shè)備做一次檢查,以免出現(xiàn)“黑盒”問題。
最后的要點
我曾以為“CSS 不能回頭看”。而現(xiàn)在,有了 :has,這種“后視鏡式”判斷終于有了原生解法。 不妨在下一個項目里試試它——因此你會得到更干凈的樣式表,然而仍然具備動態(tài)的上下文行為,最終讓代碼和布局一起“呼吸”。
感謝你的閱讀。下次我們繼續(xù)分享一個小而妙的 CSS 心得。


























