:focus-within 是 CSS 伪类选择器,当元素自身或其任意后代获得焦点时触发,适用于表单高亮、下拉菜单、可访问性增强等场景,Chrome 60+、Firefox 52+、Safari 15.4+ 支持,IE 不支持。

focus-within 是什么,什么时候能用
:focus-within 是一个 CSS 伪类选择器,当元素自身获得焦点,或其任意后代元素获得焦点时,该元素就会匹配这个选择器。它不是 JavaScript 的 focus() 方法,也不依赖 JS 监听,纯 CSS 行为。
典型使用场景:表单容器高亮、下拉菜单展开后保持外层样式、可访问性增强(比如键盘导航时整个卡片变色)。
浏览器支持从 Chrome 60、Firefox 52、Safari 15.4 开始稳定可用;IE 完全不支持,Edge 79+ 跟 Chrome 一致。如果你的项目需兼容旧版 Edge 或 IE,得用 JS 模拟(比如监听 focusin 事件并加 class)。
怎么写 focus-within 的基础语法
写法很简单::focus-within 必须挂在一个父级容器上,不能单独用于 input 或 button 这类叶子节点(虽然语法合法,但没实际意义)。
立即学习“前端免费学习笔记(深入)”;
常见错误是写成 input:focus-within —— 这永远不生效,因为 input 没有可聚焦的后代。
正确写法示例:
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
form:focus-within {
border: 2px solid #007bff;
}
div.card:focus-within input {
background: #f8f9fa;
}
注意第二行:这里给 div.card 下的 input 设置背景,前提是 div.card 本身或它的某个子元素(比如里面的 input、button、带 tabindex 的 span)获得了焦点。
focus-within 和 :focus 的关键区别
:focus 只作用于“当前被聚焦的那个元素”,而 :focus-within 作用于“包含被聚焦元素的最近祖先”。
容易踩的坑:
- 如果父容器设了
overflow: hidden且子元素聚焦后内容溢出,:focus-within仍会触发,但视觉上可能看不到变化 - 动态插入的子元素(如 JS append 的
input),只要插入后可聚焦,:focus-within立即生效,无需额外操作 - 使用
tabindex="-1"的元素也能触发:focus-within,但tabindex="-1"本身不可被 Tab 键到达,需配合 JSel.focus() -
contenteditable元素算可聚焦后代,所以div[contenteditable]:focus-within在编辑时也会命中
一个实用的表单交互代码片段
下面是一个带验证提示的输入框组,用 :focus-within 实现“一碰就高亮整个区块”:
<div class="input-group"> <label>邮箱</label> <input type="email" name="email"> <small class="error">请输入有效邮箱</small> </div>
.input-group {
padding: 8px;
border-radius: 4px;
}
.input-group:focus-within {
background: #eef7ff;
border: 1px solid #007bff;
}
.input-group .error {
opacity: 0;
transition: opacity 0.2s;
}
.input-group:focus-within .error {
opacity: 1;
}
这里的关键是:用户点进 input,.input-group 立即响应,错误提示淡入——不需要 JS 绑定 focus/blur 事件,也不用管理 class 切换状态。
真正容易被忽略的是 tabindex:如果 .input-group 内没有原生可聚焦元素(比如只有 div + span),又想让它响应键盘焦点(例如用方向键切换),就得给某个子元素加 tabindex="0",否则键盘用户永远进不去这个区域。


















