:focus-within更适合表单容器高亮,因为它作用于自身或任意后代获焦的父容器,可使整个标签区域(如包裹label与input的div)响应输入框聚焦;而:focus仅作用于获焦元素自身。

为什么 :focus-within 比 :focus 更适合表单容器高亮
单独给 <input> 加 :focus 只能改变输入框自身样式,但实际中你往往想高亮整个标签区域(比如带 <label></label> 的包裹容器),尤其是当 label 和 input 分离、或用了浮动布局时。:focus-within 会匹配**自身或其任意后代获得焦点**的元素,天然适配这种嵌套结构——只要 input 获焦,外层 <div class="form-item"> 就能响应。
<p>注意:它不兼容 IE,Edge 从 79+、Chrome 60+、Firefox 52+ 开始支持;Safari 15.4+ 才完全稳定(早期版本对 <code>contenteditable 内部焦点支持不一致)。
基础用法:给表单容器加边框高亮
典型 HTML 结构是 <div class="form-item">
<label>邮箱</label><input type="email">
</div>。CSS 直接写:
form-item:focus-within {
border: 2px solid #007bff;
border-radius: 4px;
padding: 4px;
}
关键点:
-
:focus-within必须作用于包含可聚焦子元素(input、textarea、button、带tabindex的元素)的父容器上 - 如果父容器本身不可聚焦(没设
tabindex),它仍能响应后代焦点——这是和:focus的本质区别 - 避免在
<form></form>根节点直接用,否则整个表单获焦(比如点击任意子按钮)都会触发,容易误触发
配合 label 实现点击高亮联动
用户点击 <label for="email"></label> 时,关联的 <input id="email"> 会自动获焦,此时 :focus-within 依然生效。但要注意两种常见失效场景:
- label 和 input 没正确绑定(缺少
for/id对应,或 input 没有id) - label 内部嵌套了非可聚焦内容(如
<span></span>包裹文字),而 input 在 label 外部——这时需确保 input 是 label 的**直接或间接后代** - 若用 CSS 隐藏了原生 input(如自定义 checkbox),必须保留其可聚焦性(不设
display: none或visibility: hidden),推荐用position: absolute; clip: rect(0 0 0 0)
性能与可访问性提醒
:focus-within 的重绘开销极小,但滥用会干扰键盘导航体验:
- 别在深层嵌套容器(如
<div><div><div><input></div></div></div>)上盲目加:focus-within,容易导致多层同时高亮,视觉混乱 - 高亮色对比度必须 ≥ 4.5:1(可用
color-contrast()函数或手动测),否则屏幕阅读器用户无法感知状态变化 - 如果项目需支持旧版 Safari 或 IE,得降级为 JavaScript 监听
focusin/focusout事件并手动切类名——:focus-within没有纯 CSS fallback 方案
真正难的是判断「该在哪一层容器上加」:太浅(只包 input)失去语义,太深(包整个卡片)又破坏焦点路径。动手前先用浏览器 DevTools 的 :focus-within 模拟器点几下,看高亮范围是否符合直觉。











