.container:has(:focus) 不生效是因为容器自身未设 tabindex 无法获得焦点;正确写法是 .container:has(input:focus) 或更通用的 .container:has(:focus-within)。

:has(:focus) 能让父容器响应子元素聚焦,但直接写 .container:has(:focus) 几乎总是无效——因为 :focus 只匹配自身获得焦点的元素,而容器本身通常不可聚焦,它的子元素才聚焦。
为什么 .container:has(:focus) 不生效
这个写法语义是“选择自身处于 :focus 状态的 .container”,但除非你给 .container 加了 tabindex,否则它根本不会触发 :focus。实际需求是“当子 input 聚焦时,高亮其父容器”,必须明确写出子元素路径。
-
.container:has(input:focus)✅ 匹配含聚焦input的容器 -
.container:has(.k-input-solid:focus-within)✅ 更稳妥,兼容内部嵌套input的封装组件(如 Kendo) -
.container:has(:focus)❌ 容器没加tabindex就永远不匹配
:focus vs :focus-within:选哪个更可靠
用 :focus 要求子元素**自身**获得焦点;用 :focus-within 只要子树中**任一后代**聚焦即可。多数表单场景推荐后者,尤其当输入框被包裹在 div、span 或 Shadow DOM 内时。
- 结构为
→.container:has(input:focus)可用 - 结构为
→ 必须用.container:has(:focus-within)或.container:has(div input:focus) -
:focus-within在 Safari 15.4+ 支持良好,且比多层:has()嵌套性能更好
容易忽略的兼容性与降级处理
:has() 在 Chrome 105+、Firefox 121+、Safari 15.4+ 可用,但 iOS 15.6 及更早版本完全不支持。不能只靠它做关键交互逻辑。
- 用
@supports selector(:has(*))包裹样式,避免旧浏览器解析失败崩溃 - 降级方案保留 JS 切换 class:监听
focusin/focusout事件,给容器加is-focused - 注意
display: none的子元素不会被:has()匹配——哪怕它代码里写了input,只要没渲染,就等于不存在
真正麻烦的不是写对选择器,而是确认 DOM 结构是否稳定、子元素是否始终在渲染树中、以及旧版 Safari 用户是否能接受无高亮——这些比语法本身更影响上线决策。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











