:has() 不能反向影响兄弟元素,需将悬停态提升至共同父容器,用 .card-grid:has(.card:hover) .card:not(:hover) { filter: blur(4px); } 实现模糊效果。

为什么直接用 :has() + filter: blur() 会失效?
因为 :has() 只能向上匹配祖先或同级元素,但不能“反向影响”已渲染的兄弟节点——除非你把模糊逻辑放在被悬停元素的父容器上,并让所有卡片成为它的直系子元素。常见错误是写成 .card:hover:has(~ .card),这根本不会匹配,:has() 的参数必须是选择器,且只能出现在伪类左侧(即它描述的是“当前元素是否满足内部条件”),不是用来触发其他元素样式的开关。
正确结构:用父容器状态控制兄弟模糊
核心思路是把悬停态提升到共同父容器,再用 :has() 检测某个子卡片是否被悬停,从而给其余兄弟加模糊。需确保 HTML 结构扁平:
<div class="card-grid"> <div class="card">A</div> <div class="card">B</div> <div class="card">C</div> </div>
对应 CSS:
.card-grid:has(.card:hover) .card:not(:hover) {
filter: blur(4px);
transition: filter 0.2s ease;
}
-
.card-grid:has(.card:hover)表示只要任意一个.card被悬停,整个网格就进入“激活态” -
.card:not(:hover)精确筛选出当前未被悬停的卡片 - 必须加
transition,否则模糊出现突兀;注意blur()本身不触发重排,性能尚可 - 若卡片内有交互区域(如按钮),需确保
:hover能稳定触发,避免因 padding/margin 或 pointer-events 干扰
兼容性与降级处理要点
:has() 在 Chrome 105+、Firefox 121+、Safari 15.4+ 支持,但旧版 Safari(尤其是 iOS 15.2–15.3)存在 bug:当父容器有 overflow: hidden 时,:has() 可能不响应。实际项目中建议:
- 用
@supports selector(:has(*))包裹该逻辑,避免在不支持浏览器中应用无效样式 - 降级方案可回退为 JS 监听
mouseenter/leave,动态添加类名(如.card-grid--hovering),CSS 中用类名代替:has() - 避免在
:has()内使用过于复杂的嵌套选择器(如.card > .content:hover),部分浏览器解析不稳定
为什么不能对 :not(:hover) 单独加 transition?
因为 :not(:hover) 是动态计算的伪类,其匹配状态随鼠标移动高频变化,若每个卡片都独立声明 transition,会导致大量样式重计算和闪烁。统一由父容器控制、只在一个地方声明 transition,更稳定也更易调试。另外,如果卡片本身有 transform 或 opacity 动画,filter: blur() 会强制创建新层叠上下文,可能影响 z-index 行为——这点容易被忽略,尤其当卡片带阴影或遮罩时。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











