
本文介绍如何利用 CSS 的 :focus-within 伪类,在不依赖 JavaScript 的前提下,使巨型菜单既支持鼠标悬停展开,也支持键盘 Tab 导航聚焦时自动展开,提升无障碍访问体验。
本文介绍如何利用 css 的 `:focus-within` 伪类,在不依赖 javascript 的前提下,使巨型菜单既支持鼠标悬停展开,也支持键盘 tab 导航聚焦时自动展开,提升无障碍访问体验。
在构建符合无障碍标准(WCAG)的导航组件时,仅靠 :hover 实现巨型菜单展开是不够的——键盘用户(如使用 Tab 键导航的视障人士或偏好键盘操作的用户)无法触发菜单显示,导致功能不可达。原方案尝试对 <li> 元素设置 tabindex="1" 并监听 :focus,但因 <li> 默认不可聚焦(且内部 <a> 才是实际获得焦点的元素),导致 li:focus 永远不会匹配,菜单无法响应 Tab 操作。
解决方案是采用现代 CSS 中专为该场景设计的 :focus-within 伪类:当元素自身或其任意后代元素获得焦点时,该选择器即生效。由于 <a> 是 <li class="has-children"> 的直接子元素且天然可聚焦,只需将触发规则从 li:focus 改为 li:focus-within,即可完美覆盖键盘导航场景。
以下是关键 CSS 修改部分(其余样式保持不变):
/* 替换原规则 */
li.has-children:hover .mm-cont,
li.has-children:focus-within .mm-cont {
display: flex;
}✅ 优势说明:
立即学习“前端免费学习笔记(深入)”;
- 零 JS 依赖:纯 CSS 实现,轻量、可靠、无运行时风险;
- 无障碍友好:满足 WCAG 2.1 “键盘可操作”(2.1.1)与“焦点可见性”(2.4.7)要求;
- 语义清晰:无需额外 ARIA 属性(如 aria-expanded),但建议仍配合 aria-haspopup="true" 和 aria-expanded 属性增强语义(由 JS 或服务端动态控制更佳);
- 兼容性良好:主流浏览器(Chrome 65+、Firefox 61+、Safari 15.4+、Edge 79+)均支持;旧版 Safari 可通过 @supports 回退至仅 hover。
⚠️ 注意事项:
- 确保 <a> 标签始终存在于 <li class="has-children"> 内部,且未被 pointer-events: none 或 tabindex="-1" 等阻止聚焦;
- 避免对 .mm-cont 设置 tabindex,否则焦点会落入菜单内部,破坏导航流顺序;
- 若需支持更复杂的交互(如 Esc 关闭、方向键导航),则需引入 JavaScript —— 但基础展开/收起完全可由 :focus-within + :hover 覆盖。
最终效果:用户从输入框按 Tab 键,焦点移入“Lorem”链接 → <li> 因其子元素 <a> 获焦而匹配 :focus-within → .mm-cont 显示;再次 Tab 则焦点移至下一个 <li>,当前菜单自动隐藏(因失去 :focus-within 状态),行为自然且符合用户预期。


















