:focus-within

检测内部元素的焦点状态

什么是 :focus-within?

:focus-within 伪类用于选择自身或其后代元素获得焦点的元素。 这是一个非常实用的选择器,可以让我们在内部元素获得焦点时,改变父容器的样式。

与传统的 :focus 只能选择获得焦点的元素本身不同, :focus-within 可以向上传播,让父元素也能响应内部元素的焦点状态。 这在表单设计、搜索框、对话框等场景中特别有用。

💡 核心特性:
  • 当元素自身或任何后代元素获得焦点时匹配
  • 焦点状态向上传播到所有祖先元素
  • 支持嵌套元素的焦点检测
  • 无需 JavaScript 即可实现父容器响应

语法

/* 基础语法 */
element:focus-within {
  /* 当 element 或其后代获得焦点时的样式 */
}

/* 实际应用示例 */
form:focus-within {
  border-color: blue;
  box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.1);
}

/* 嵌套使用 */
.container:focus-within .label {
  color: var(--primary);
  font-weight: 600;
}
⚠️ 与 :has(:focus) 的对比:
  • :focus-within - 专门用于焦点检测,性能更好,浏览器支持更早
  • :has(:focus) - 更通用的父选择器,但性能稍差,浏览器支持较晚
  • 对于焦点检测场景,推荐使用 :focus-within

示例 1: 表单容器焦点效果

当表单内的任何输入框获得焦点时,整个表单容器会改变样式,提供清晰的视觉反馈。

效果预览 - 点击或 Tab 到输入框

用户注册

表单未激活
/* 表单容器焦点样式 */
.focus-form:focus-within {
  border-color: var(--primary);
  background: var(--primary-light);
  box-shadow: 0 0 0 4px rgba(16, 185, 129, 0.1);
}

/* 标题响应焦点状态 */
.focus-form:focus-within h3 {
  color: var(--primary);
}

/* 当前获得焦点的输入框的标签高亮 */
.form-group:focus-within label {
  color: var(--primary);
  font-weight: 600;
  transform: translateX(4px);
}

/* 焦点指示器 */
.focus-form:focus-within .focus-indicator {
  background: var(--primary);
  color: white;
}

示例 2: 嵌套元素的焦点传播

:focus-within 会向上传播到所有祖先元素,这使得多层嵌套的布局也能响应内部元素的焦点状态。

效果预览 - 观察多层容器的响应
🟡 外层容器 (Outer)

当内部任何输入框获得焦点时,我会变成橙色边框

🟣 中层容器 (Middle)

当内部输入框获得焦点时,我会变成紫色边框

🟢 内层容器 (Inner)
/* 外层容器 */
.outer-container:focus-within {
  border-color: #f59e0b;
  background: rgba(245, 158, 11, 0.05);
}

.outer-container:focus-within > .container-label {
  color: #f59e0b;
}

/* 中层容器 */
.middle-container:focus-within {
  border-color: #8b5cf6;
  background: rgba(139, 92, 246, 0.05);
}

.middle-container:focus-within > .container-label {
  color: #8b5cf6;
}

/* 内层容器 */
.inner-container:focus-within {
  border-color: var(--primary);
  background: var(--primary-light);
}

.inner-container:focus-within > .container-label {
  color: var(--primary);
}

实际应用场景

以下是三个常见的实际应用场景,展示 :focus-within 如何提升用户体验。

场景 1: 搜索框容器焦点效果

🔍
/* 搜索框容器获得焦点时的样式 */
.search-container:focus-within {
  border-color: var(--primary);
  box-shadow: 0 0 0 4px rgba(16, 185, 129, 0.1);
  background: var(--primary-light);
}

/* 图标颜色变化 */
.search-container:focus-within .search-icon {
  color: var(--primary);
}

/* 搜索按钮显示动画 */
.search-container:focus-within .search-btn {
  opacity: 1;
  transform: scale(1);
  background: var(--primary);
  color: white;
}

场景 2: 登录表单焦点高亮

/* 登录卡片获得焦点时提升 */
.login-card:focus-within {
  border-color: var(--primary);
  box-shadow: 0 8px 24px rgba(16, 185, 129, 0.15);
  transform: translateY(-2px);
}

/* 标题颜色变化 */
.login-card:focus-within h3 {
  color: var(--primary);
}

/* 当前字段标签高亮 */
.login-field:focus-within label {
  color: var(--primary);
  transform: translateX(4px);
}

/* 提交按钮激活 */
.login-card:focus-within .login-submit {
  background: var(--primary);
  color: white;
}

场景 3: 评论框焦点状态

👤
当前用户
/* 评论框获得焦点时的样式 */
.comment-box:focus-within {
  border-color: var(--primary);
  background: var(--primary-light);
}

/* 头像动画 */
.comment-box:focus-within .comment-avatar {
  background: var(--primary);
  transform: scale(1.1);
}

/* 操作按钮显示 */
.comment-box:focus-within .comment-actions {
  opacity: 1;
}

/* 工具按钮渐入动画 */
.comment-box:focus-within .comment-tool {
  transform: translateY(0);
  opacity: 1;
}

/* 提交按钮激活 */
.comment-box:focus-within .comment-submit {
  background: var(--primary);
  color: white;
}

浏览器兼容性

:focus-within 在现代浏览器中有良好的支持,是一个可以放心使用的特性。

浏览器 版本支持 发布时间
🌐 Chrome / Edge ✓ 60+ 2017年7月
🦊 Firefox ✓ 52+ 2017年3月
🧭 Safari ✓ 10.1+ 2017年3月
📱 iOS Safari ✓ 10.3+ 2017年3月
💡 使用建议:
  • 优先使用 - 相比 :has(:focus):focus-within 性能更好且支持更早
  • 渐进增强 - 即使不支持,也不会影响基本功能,只是缺少视觉增强
  • 无障碍友好 - 配合键盘导航使用,提升可访问性
  • 避免过度使用 - 不要在每个元素上都使用,保持性能
⚠️ 注意事项:
  • IE 浏览器不支持 :focus-within
  • 如需支持旧版浏览器,可以使用 JavaScript polyfill
  • 避免在 :focus-within 中使用复杂的动画,可能影响性能

→ 查看完整的浏览器兼容性数据 (Can I Use)

总结

:focus-within 是一个强大且实用的伪类选择器,它让我们能够在不使用 JavaScript 的情况下, 根据内部元素的焦点状态来改变父容器的样式。

🎯 核心要点:
  • 当元素自身或后代元素获得焦点时匹配
  • 焦点状态向上传播到所有祖先元素
  • 非常适合表单、搜索框、对话框等交互场景
  • 相比 :has(:focus) 性能更好,浏览器支持更早
  • 配合过渡动画可以创造流畅的用户体验

在下一个演示中,我们将学习 :focus-visible, 它可以帮助我们区分鼠标点击和键盘导航的焦点状态,进一步优化用户体验。