:focus-within能控制整行高亮,因其作用于父容器时,只要子元素(如input)获焦即触发样式;须写在父级(如label)而非input自身,且需注意浏览器兼容性与overflow、shadow DOM等限制。

focus-within 为什么能控制整行高亮
:focus-within 是 CSS 原生伪类,只要元素自身或其任意后代获得焦点(比如 <input> 被点击),该元素就会匹配。它不依赖 JS,也不需要监听事件,天然适合“父容器响应子输入框聚焦”这类场景。
常见错误是把 :focus-within 写在 <input> 上——没用,<input> 自身用 :focus 就够了;真正要加的是它的**父级容器**,比如 <div class="row"> 或 <code><label></label>。
- 只支持现代浏览器:Chrome 65+、Firefox 61+、Safari 15.4+(iOS Safari 15.4+),IE 完全不支持
- 若父元素设了
overflow: hidden且子 input 滚动出视口,部分旧版 Safari 可能触发异常行为 - 和
:has()不同,:focus-within性能开销极低,浏览器原生优化过
怎么写才让整行背景/边框一起变色
关键在于把样式规则作用于包裹 <input> 的容器,并用 :focus-within 触发:
label:focus-within {
background-color: #f0f8ff;
border-left: 3px solid #2196f3;
}
使用场景典型如表单行:<label><span>用户名</span><input type="text"></label>。注意:<label></label> 必须是 <input> 的**有效祖先**(不能被 display: contents 中断,也不能跨 shadow DOM)。
立即学习“前端免费学习笔记(深入)”;
- 避免用
div:focus-within包太多无关内容,否则焦点一进就全亮,体验反而乱 - 如果行内有多个可聚焦元素(如
<input>+<button></button>),任一获得焦点都会触发,需确认这是预期行为 - 不要给父容器设
tabindex="-1",这会干扰:focus-within的判定逻辑
和 JavaScript 方案比,差在哪
纯 CSS 的 :focus-within 在绝大多数表单场景下更轻量、更可靠。JS 方案常靠监听 focusin/focusout 手动增删 class,但容易漏掉 click → focus → blur → click 的快速切换,或在 iframe、shadow DOM 边界失效。
- JS 需处理
blur时判断是否移出了整行(要用relatedTarget和递归检查),CSS 不用操心这个 - 如果输入框是动态插入的,JS 需重新绑定事件;
:focus-within自动生效,无绑定成本 - 当页面有大量表单项时,JS 的事件监听器堆积可能引发内存泄漏,CSS 无此风险
移动端软键盘弹起时的兼容问题
Safari iOS 15.4 之前版本对 :focus-within 的支持不稳定:软键盘弹出后,有时不触发,有时失焦时不还原。这不是你代码写错了,是浏览器 bug。
- 临时缓解:给
<input>加onfocus="this.parentElement.classList.add('focused')",配合 JS 清除,仅针对 iOS 降级 - 别依赖
:focus-within做关键功能(比如权限校验或提交拦截),它只是视觉反馈层 - 测试务必真机连 Safari 开发者工具,模拟器经常表现正常但真机翻车
真正难的不是写对那行 CSS,而是想清楚「谁该当父容器」和「失焦边界在哪里」——这两个点错一个,效果就断在最不该断的地方。


















