前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库CSS :focus-within pseudo-class usability
CSS层叠与选择器

focus-within 伪类有什么用?和 focus 的区别是什么?

:focus-within 在元素自身或者它的任意后代获得焦点时匹配。比如用户在表单里某个输入框打字,用 :focus-within 可以给整个表单容器加一个高亮边框,不需要 JavaScript。

前端进阶之旅 · 一题精讲更新于 2026.09.29
CSS#层叠与选择器#表单
先看核心答案读代码示例
理解线索

焦点的两种匹配范围

  1. :focus只匹配直接获得焦点的那个元素
  2. :focus-within匹配获焦元素及其所有祖先
  3. 冒泡行为焦点在深层子元素上时,所有层级的祖先都匹配

:focus-within 失焦后立刻消失。焦点从一个子元素移到另一个子元素时,父容器一直保持匹配状态,不会闪烁。

核心回答

先记住这个答案

:focus-within 的匹配范围比 :focus 大。:focus 只匹配直接获得焦点的那个元素,:focus-within 不仅匹配它本身,还匹配它的所有祖先元素。这意味着当用户在 <input> 里打字时,包裹这个输入框的 <div>、<form> 乃至 <body> 都会匹配 :focus-within。

  • 后代获焦时祖先也匹配
  • 常用于表单容器高亮
  • 会一直冒泡到根元素
  • 和 :focus 可以同时生效

最典型的场景:表单输入时高亮容器

表单设计中经常需要让用户知道「当前在填哪一组」。以前只能用 JavaScript 监听 focus 和 blur 事件,给容器加类名。现在用 :focus-within 一行 CSS 就能搞定。

输入框聚焦时高亮整个表单组CSS
/* 任何子元素获焦时,给表单组加边框和背景 */
.form-group:focus-within {
  border-color: #1890ff;
  background-color: #f0f7ff;
}

/* 同时让标签变色 */
.form-group:focus-within label {
  color: #1890ff;
}

用户点进输入框的时候,.form-group 整个容器会变成蓝色边框加淡蓝背景,标签文字也变蓝。点到其他输入框或者点击空白处,样式自动恢复。焦点在同一个 .form-group 里的不同子元素之间切换时,容器一直保持高亮,不会闪烁。

用 focus-within 做纯 CSS 下拉菜单

:focus-within 还有一个巧妙的用法:做不需要 JavaScript 的下拉菜单。思路是让菜单容器在获得焦点(或者后代获得焦点)时显示子菜单。

键盘可访问的下拉菜单CSS
.dropdown-menu {
  display: none;
}

/* 容器或其后代获焦时显示菜单 */
.dropdown:focus-within .dropdown-menu {
  display: block;
}

用户用 Tab 键聚焦到下拉按钮时,菜单显示出来。继续按 Tab 切换菜单项时,焦点仍在 .dropdown 的后代里,菜单保持显示。焦点移出整个 .dropdown 后,:focus-within 失效,菜单消失。 这种方式比 :hover 做下拉菜单好,因为它对键盘用户友好。:hover 在手机上还有粘滞问题,:focus-within 没有。

冒泡到根元素

:focus-within 的匹配会一直冒泡到 DOM 树的根元素。焦点在一个深层嵌套的 <input> 上,从 <input> 的直接父元素到 <html>,每一层都匹配 :focus-within。

这个特性可以用来实现一些全局效果。比如页面上有搜索框时,用户开始输入就给整个页面加一层半透明遮罩,引导注意力集中在搜索区域。

不用担心性能问题。浏览器对 :focus-within 的计算做了优化,它只在焦点变化时重新评估,不会像 :hover 那样随着鼠标移动频繁触发。

回答前,多想一步

容易答错的地方

以为 focus-within 是继承
:focus-within 不是 CSS 继承。继承是父元素的属性值传给子元素,:focus-within 是子元素的焦点状态让父元素匹配伪类。方向正好相反:继承从上往下传值,:focus-within 从下往上传状态。
以为焦点在子元素间切换时会闪
焦点从一个 <input> 移到同一容器内的另一个 <input> 时,:focus-within 不会出现「先消失再出现」的闪烁。浏览器会先让新元素获焦,再让旧元素失焦,中间容器的 :focus-within 一直成立。
试着用自己的话回答

面试官还会怎么问?

focus-within 和 has(:focus) 有什么区别?

功能上几乎一样,:focus-within 等价于 :has(:focus)。但 :focus-within 浏览器支持更早更广,:has() 是后来才普及的。如果只是需要「后代聚焦时父元素匹配」,用 :focus-within 更直接。

focus-within 在可访问性方面有什么好处?

:focus-within 让键盘用户和鼠标用户看到相同的视觉反馈。用户用 Tab 键进入表单组时,容器高亮效果和鼠标点击一样,不需要额外的 JavaScript 适配。这对无障碍访问是天然的加分项。

怎么只让直接子元素聚焦时匹配,不冒泡到更上层?

:focus-within 本身没有「只看直接子元素」的选项,它天然会冒泡到所有祖先。如果只想对直接子元素聚焦做响应,可以用 :has(> :focus) 来精确控制匹配层级。

从一道题,走向一组知识

把知识连起来

层叠与选择器

required 和 optional 伪类怎么用?匹配哪些表单元素?

:focus-within 看后代焦点,:required 看控件必填约束;表单容器可分别使用它们。

层叠与选择器

target 伪类是怎么根据 URL 的 hash 来匹配元素的?

:target 根据 URL 片段匹配,和焦点状态并非同一回事。

参考资料

  • CSS:层叠与选择器参考资料

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 最典型的场景:表单输入时高亮容器
  3. 用 focus-within 做纯 CSS 下拉菜单
  4. 冒泡到根元素
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑