不能直接用 .card:hover { transform: scale(1.05) } 是因为缺少 transition 声明,导致无动画效果;必须在基础态(如 .card)中设置 transition: transform 0.3s ease,并配合 transform-origin: center、overflow: hidden 和 z-index: 2 防溢出、偏移与遮挡。

为什么不能直接用 .card:hover { transform: scale(1.05) }?
因为 :has() 和 hover 放大是两件事——前者解决“反向控制”,后者解决“视觉反馈”。你真正需要的,是当某个特定卡片(比如第3张)被悬停时,让页面中另一个独立区域(如侧边预览栏、顶部摘要区)同步放大显示对应内容。纯 .card:hover 只能影响自身,无法跨结构触发远端元素变化。
:has() + :hover 组合必须写在公共父容器上
浏览器不支持 .overlay-one:has(.card:nth-child(3):hover) 这类写法——:has() 只能出现在选择器左侧,且必须向上匹配祖先,不能向下或向同级“找”悬停源。正确路径是:把所有卡片和目标 overlay 包进同一个父容器(如 .gallery),然后用 .gallery:has(.card:nth-child(3):hover) 去驱动后续兄弟元素。
- 确保 HTML 中
.card和.overlay-one是.gallery的直属子元素(顺序不限,但必须同级) -
:nth-child(N)按 DOM 顺序计数,不是按 class 名或数据属性;若卡片中间插了<div></div>,nth-child(3)就可能错位 - Chrome 105+ / Firefox 121+ / Safari 15.4+ 支持,Edge 同步 Chrome 内核,无需额外前缀
放大动画必须搭配 transition 才生效
仅靠 :has() 匹配成功后设置 transform: scale(1.05),不会产生过渡动画——它只是“开关式”显隐或突变。要平滑缩放,得在目标元素的基础样式里声明 transition:
.overlay-one {
transform: scale(1);
transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
opacity: 0;
}
.gallery:has(.card:nth-child(1):hover) ~ .overlay-one {
transform: scale(1.05);
opacity: 1;
}
-
transition必须写在非:has()触发的默认规则里,否则第一次匹配时会“跳” - 避免用
transition: all,它会让opacity、background-color等也参与过渡,可能干扰预期效果 - 如果放大后边缘发虚,加
will-change: transform到.overlay-one基础样式中,提示浏览器启用合成层
移动端点击后立即消失?这是 :hover 的固有缺陷
iOS Safari 和多数安卓 WebView 中,:hover 仅在触摸后短暂激活,且不维持状态——这意味着 :has(.card:hover) 在真机上几乎无法稳定触发。不要依赖它做核心功能。
- 测试务必用真机点按,Chrome 模拟器的 “Toggle device toolbar” 会高估 hover 可靠性
- 替代方案:用 JavaScript 监听
touchstart给卡片加data-hovered="true",再改用.gallery:has(.card[data-hovered="true"]) - 更轻量的做法:放弃
:has(),直接用 JS 切换.overlay-one.is-active类,CSS 只管动画逻辑
:has() 的 DOM 位置约束和移动端的 hover 失效边界——它们不是“写了就能跑”,而是需要配合 HTML 结构设计和降级策略一起落地。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











