:focus-within必须作用于包含可聚焦子元素的父容器(如div、fieldset),不能直接写在input上;父容器需具备可聚焦上下文(如tabindex="-1"或语义化标签),否则伪类永不匹配。

为什么:focus-within加在input上永远不生效
因为 :focus-within 不是 :focus 的替代品,它专为“监听者”设计——必须写在能包含可聚焦子元素的父容器上。浏览器直接忽略 .input:focus-within 这类写法,input 是叶子节点,没有后代可监听。
真正要高亮整个表单组,得把伪类加在包裹它的 div、label 或 fieldset 上。只要内部有 input、textarea、button 或带 tabindex 的元素获焦,样式就触发。
-
input:focus改的是输入框自身(边框、阴影等) -
.form-group:focus-within改的是整个区域(背景、边框、嵌套提示文字等) - React/Vue 中自定义组件如
<myinput></myinput>,需确保原生input没被设tabindex="-1"或pointer-events: none
父容器没加tabindex="-1"就失效
纯 div 默认不可参与焦点流,:focus-within 不会计算——这不是 bug,是规范行为。它不要求父容器被 tab 进去,但必须处于“可聚焦上下文”中。
✅ 推荐:<div class="form-group" tabindex="-1"> —— 仅需一次,不干扰 tab 顺序,也不影响语义。
<p>❌ 错误:<code><div class="form-group"> —— 没有任何聚焦能力,伪类永不匹配。
<ul>
<li>语义化标签如 <code>form、fieldset 天然支持,不用额外加 tabindex
form 加 :focus-within,点任意按钮也会触发,容易误高亮display: contents 或 visibility: hidden 包裹子元素,焦点链断裂,伪类照样失效高亮样式一改margin或height就翻车
很多“失效”其实是视觉副作用导致的:重排、跳动、覆盖文字、边框错位。这些不是伪类没生效,而是样式破坏了渲染稳定性。
优先用 outline: 2px solid #007bff:不占空间、无重排、键盘导航友好。
要用阴影,选 box-shadow: 0 0 0 2px rgba(0,123,255,0.25),别加 inset——否则往里缩,盖住输入内容。
- 绝对别在
:focus-within规则里改height、margin或display,尤其在表格中tr高度变化会整行跳动 - 统一所有相关元素的
box-sizing为border-box,避免padding+border导致宽度溢出 - 避免同时用
outline和border,容易重叠或偏移
Safari 15.4 之前和 IE 完全不支持
Chrome 60+、Firefox 52+、Edge 79+ 都支持,但 Safari 直到 15.4 才完全稳定(早期对 contenteditable 内部焦点支持不一致),IE 则完全不支持。
如果项目需兼容旧版 Safari 或企业内网 IE,不能只靠 CSS;得降级为 JS 监听 focusin/focusout 并手动切类名。
验证是否真生效:打开 DevTools,点击输入框后运行 document.activeElement,返回值必须是预期的 input 元素——如果不是,说明焦点被封装组件劫持或未透出。
复杂点在于,失效往往不在 CSS 写法本身,而在 DOM 结构、焦点链完整性或 shadow DOM 穿透限制上,调试时得一层层确认焦点落点。











