:focus-within 必须写在能包含可聚焦后代的父容器上才生效,input 等叶子节点无法触发;父容器需具备可聚焦上下文(如加 tabindex="-1" 或使用 form/fieldset),且样式避免引发重排。

:focus-within 必须写在父容器上才生效,加在 input 上永远没反应。
为什么 .input:focus-within 永远不触发
浏览器根本不会匹配这个写法——:focus-within 不是 :focus 的替代品,它只对“能包含可聚焦后代”的祖先元素起作用。input 是叶子节点,没有后代,所以伪类被直接忽略。
- 错误写法:
.input:focus-within、input:focus-within - 正确目标:包裹
input的div、label、fieldset或form - 检查 DevTools 元素面板,确认焦点是否真落在
input上(而不是外层div被 JS 抢了焦点)
父容器没加 tabindex="-1" 就失效
纯 div 默认不在焦点流中,:focus-within 不会计算它——这不是 bug,是规范行为。它不要求父容器被 tab 进去,但必须处于“可聚焦上下文”里。
- ✅ 推荐:
<div class="form-group" tabindex="-1"> —— 仅需一次,不干扰 tab 顺序 <li>❌ 错误:<code><div class="form-group"> —— 没有任何聚焦能力,伪类永不匹配 <li>语义化标签如 <code>form、fieldset天然支持,不用额外加tabindex - 别给整个
form加:focus-within,点任意按钮也会触发,容易误高亮 - 优先用
outline: 2px solid #007bff:不占空间、无重排、键盘导航友好 - 要用阴影,选
box-shadow: 0 0 0 2px rgba(0,123,255,0.25),别加inset,否则往里缩盖住内容 - 避免在
:focus-within规则里改height、margin、display或padding - 统一所有相关元素的
box-sizing: border-box - 确保原生
input渲染出来且未被样式或属性拦截 -
label和input必须构成祖先-后代关系(<label><input></label>或<label for="x"></label><input id="x">) - 若用
display: contents或visibility: hidden包裹子元素,焦点链断裂,伪类照样失效 - Shadow DOM 内使用时,
:focus-within必须写在 shadow host 上,且子元素焦点需能穿透出来
高亮样式一改 margin 或 height 就翻车
很多“失效”其实是视觉副作用导致的:重排、跳动、覆盖文字、边框错位。这些不是伪类没生效,而是样式破坏了渲染稳定性。
React/Vue 自定义组件里容易漏掉的点
封装的 <myinput></myinput> 组件若内部 input 被设了 tabindex="-1" 或 pointer-events: none,焦点链就断了,:focus-within 自然不触发。
真正要让表单区域联动高亮,关键不是写对伪类,而是确认焦点链完整、容器有上下文、样式不破坏布局——三者缺一不可。











