:focus-visible

智能显示焦点环,优化键盘导航体验

什么是 :focus-visible?

:focus-visible 伪类用于选择应该显示焦点指示器的元素。 它解决了传统 :focus 的一个重要问题:当用户用鼠标点击按钮时, 通常不需要显示焦点环,但当用户使用键盘导航时,焦点环是必不可少的。

浏览器会根据用户的输入方式(鼠标、触摸、键盘)智能判断是否需要显示焦点指示器。 这让我们能够在保持良好无障碍访问的同时,提供更清爽的视觉体验。

💡 核心特性:
  • 智能判断 - 浏览器根据输入方式决定是否显示焦点环
  • 键盘友好 - 使用 Tab 键导航时始终显示焦点指示器
  • 鼠标优化 - 鼠标点击按钮时通常不显示焦点环
  • 无障碍访问 - 确保键盘用户能清楚看到当前焦点位置
⚠️ 与 :focus 的关键区别:
  • :focus - 元素获得焦点时总是匹配,无论输入方式
  • :focus-visible - 只在应该显示焦点指示器时匹配
  • 使用 :focus-visible 可以避免鼠标点击时出现不必要的焦点环

语法

/* 基础语法 */
element:focus-visible {
  /* 只在应该显示焦点指示器时的样式 */
}

/* 推荐的最佳实践 */
button:focus {
  outline: none; /* 移除默认焦点环 */
}

button:focus-visible {
  outline: 3px solid var(--primary); /* 只在键盘导航时显示 */
  outline-offset: 2px;
}

/* 组合使用 */
input:focus-visible {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.1);
}
💡 使用建议:
  • 不要完全移除焦点样式 - 始终为 :focus-visible 提供清晰的样式
  • 保持高对比度 - 确保焦点指示器在任何背景下都清晰可见
  • 使用 outline 而非 border - outline 不会影响布局,更适合焦点指示器
  • 添加 outline-offset - 让焦点环与元素保持一定距离,更美观

示例 1: 鼠标点击 vs 键盘导航对比

下面的示例展示了 :focus:focus-visible 的行为差异。 请分别用鼠标点击键盘 Tab 键来测试按钮的焦点效果。

效果预览 - 请用鼠标和键盘分别测试
❌ 传统方式

使用 :focus

无论用鼠标还是键盘,获得焦点时都会显示焦点环

✅ 现代方式

使用 :focus-visible

鼠标点击不显示焦点环,键盘导航时才显示

🧪 测试步骤:
1️⃣ 用鼠标点击左侧按钮 → 会看到橙色焦点环(不理想)
2️⃣ 用鼠标点击右侧按钮 → 不会显示焦点环(更清爽)
3️⃣ 用Tab 键导航到两个按钮 → 都会显示焦点环(保证可访问性)
/* ❌ 传统方式 - 总是显示焦点环 */
.btn-old-focus:focus {
  outline: 3px solid #f59e0b;
  outline-offset: 3px;
}

/* ✅ 现代方式 - 智能显示焦点环 */
.btn-new-focus:focus {
  outline: none; /* 移除默认样式 */
}

.btn-new-focus:focus-visible {
  outline: 3px solid #f59e0b;
  outline-offset: 3px;
}

/* 结果:
 * - 鼠标点击:不显示焦点环
 * - 键盘导航:显示焦点环
 * - 最佳用户体验!
 */

示例 2: 交互式焦点测试工具

这个工具可以帮助你直观地理解不同输入方式下焦点状态的变化。

🖱️ 鼠标模式
⌨️ 键盘模式
当前焦点状态
未获得焦点
/* 测试元素样式 */
.test-element:focus {
  outline: none; /* 移除默认焦点环 */
}

.test-element:focus-visible {
  outline: 4px solid var(--primary);
  outline-offset: 2px;
  background: var(--primary-light);
}

/* JavaScript 检测焦点状态 */
element.addEventListener('focus', () => {
  // 检查是否匹配 :focus-visible
  const hasFocusVisible = element.matches(':focus-visible');
  
  if (hasFocusVisible) {
    console.log('键盘导航 - 显示焦点环');
  } else {
    console.log('鼠标点击 - 不显示焦点环');
  }
});

示例 3: 不同元素的焦点可见性策略

不同类型的元素需要不同的焦点策略。按钮通常不需要在鼠标点击时显示焦点环, 但输入框和链接的焦点行为可能有所不同。

效果预览 - 测试不同元素的焦点行为

🔘 按钮 (Buttons)

策略:使用 :focus-visible,鼠标点击时不显示焦点环,键盘导航时显示。 这是最常见的使用场景。

💡 为什么? 按钮点击后通常会触发某个动作,用户的注意力会转移到动作结果上, 不需要持续显示焦点环。但键盘用户需要知道当前焦点位置。

🔗 链接 (Links)

策略:使用 :focus-visible,行为与按钮类似。 鼠标点击时不显示焦点环,键盘导航时显示。

💡 为什么? 链接的焦点行为应该与按钮一致。用户点击链接后会跳转到新页面, 不需要在当前页面保持焦点指示器。

📝 输入框 (Inputs)

策略:使用 :focus,无论鼠标还是键盘都显示焦点状态。 输入框是个例外,不应该使用 :focus-visible

💡 为什么? 输入框获得焦点后,用户需要在其中输入内容,焦点状态应该始终可见, 无论是通过鼠标点击还是键盘导航进入的。这有助于用户知道当前正在编辑哪个字段。
/* 按钮:使用 :focus-visible */
.demo-button:focus {
  outline: none;
}

.demo-button:focus-visible {
  outline: 3px solid var(--primary);
  outline-offset: 3px;
}

/* 链接:使用 :focus-visible */
.demo-link:focus {
  outline: none;
}

.demo-link:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 4px;
}

/* 输入框:使用 :focus(不用 :focus-visible) */
.demo-input:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.1);
  outline: none;
}

无障碍访问最佳实践

使用 :focus-visible 时,务必遵循无障碍访问的最佳实践, 确保所有用户都能获得良好的体验。

✅ 推荐做法:
  • 始终提供焦点样式 - 不要完全移除焦点指示器,只是智能地显示它
  • 保持高对比度 - 焦点环应该在任何背景下都清晰可见(至少 3:1 对比度)
  • 使用 outline 而非 border - outline 不影响布局,避免元素跳动
  • 添加 outline-offset - 让焦点环与元素保持距离,更美观且更易识别
  • 测试键盘导航 - 确保所有交互元素都可以通过 Tab 键访问
  • 输入框例外 - 输入框应该始终显示焦点状态,使用 :focus 而非 :focus-visible
❌ 避免的做法:
  • 不要完全移除焦点样式 - outline: none 必须配合 :focus-visible 使用
  • 不要使用低对比度颜色 - 浅灰色焦点环对视力障碍用户不友好
  • 不要依赖颜色 - 除了颜色变化,还应该有其他视觉提示(如边框、阴影)
  • 不要在所有元素上使用 :focus-visible - 输入框等需要持续显示焦点的元素应该使用 :focus

浏览器兼容性

:focus-visible 是一个相对较新的特性,但在现代浏览器中已经得到了广泛支持。

浏览器 版本支持 发布时间
🌐 Chrome / Edge ✓ 86+ 2020年10月
🦊 Firefox ✓ 85+ 2021年1月
🧭 Safari ✓ 15.4+ 2022年3月
📱 iOS Safari ✓ 15.4+ 2022年3月
💡 使用建议:
  • 渐进增强 - 旧版浏览器会回退到 :focus 行为,不影响基本功能
  • Polyfill 可用 - 如需支持旧版浏览器,可以使用 focus-visible polyfill
  • 特性检测 - 可以使用 @supports selector(:focus-visible) 检测支持情况
  • 现代项目推荐 - 如果不需要支持旧版浏览器,可以放心使用
⚠️ 注意事项:
  • IE 浏览器完全不支持 :focus-visible
  • Safari 15.4 之前的版本不支持,但可以使用 polyfill
  • 在不支持的浏览器中,:focus-visible 规则会被忽略
  • 建议同时保留 :focus 样式作为降级方案

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

总结

:focus-visible 是现代 Web 开发中非常重要的伪类选择器, 它让我们能够在保持良好无障碍访问的同时,提供更清爽的视觉体验。

🎯 核心要点:
  • 浏览器根据输入方式智能判断是否显示焦点指示器
  • 鼠标点击按钮时不显示焦点环,键盘导航时显示
  • 输入框应该使用 :focus 而非 :focus-visible
  • 始终为 :focus-visible 提供清晰的焦点样式
  • 使用 outline 而非 border 实现焦点指示器
  • 配合 outline-offset 让焦点环更美观

通过合理使用 :focus-visible,我们可以创造出既美观又易用的界面, 让鼠标用户和键盘用户都能获得最佳体验。这是现代 Web 无障碍访问的重要实践。

在下一个演示中,我们将学习 :nth-child() 的高级用法, 探索如何使用 An+B 语法实现复杂的元素选择模式。