站点导航可访问性问题:回车键无法打开子导航,空格键触发后子导航闪灭
问题根因
- 事件绑定层级错误:你将
click和keypress事件绑定在了父级li元素上,而非作为交互触发器的button元素。当聚焦在button上按下空格/回车时,button自带的默认点击行为会触发一次冒泡到li的click事件,加上你绑定在li上的keypress事件会先触发一次,导致toggleItem连续执行两次,子菜单刚被打开就被关闭,表现为闪现。 keypress事件已被废弃,不同浏览器对回车、空格的触发逻辑存在兼容性差异,是回车无响应的核心原因之一。- 属性绑定逻辑错误:
aria-expanded是可交互触发元素(button)的属性,你当前将属性设置到了li元素上,且状态值写反:新增submenu-active激活状态时,aria-expanded应设为true,你的代码里设为了false。 - 变量未定义:代码中直接使用的
site_menu没有提前声明赋值,会触发JS报错,打断逻辑执行。
优化方案
- 调整事件绑定对象:将事件直接绑定到子菜单触发button上,避免重复触发问题
- 替换
keypress为标准的keydown事件,仅监听回车、空格两个触发键,同时阻止默认行为避免重复触发 - 修正
toggleItem的状态逻辑,正确设置aria-expanded属性 - 补充缺失的
site_menu变量声明 - 优化关闭逻辑,ESC关闭后将焦点返回触发按钮,符合可访问性规范
以下是修正后的完整JS代码:
// 补充缺失的site_menu声明 const site_menu = document.querySelector(".site-menu"); const items = document.querySelectorAll(".site-menu__item--has-submenu"); const subButtons = document.querySelectorAll(".site-menu__item--has-submenu button"); // 激活子菜单 function toggleItem(e) { // 键盘事件仅响应回车和空格 if (e.type === 'keydown' && !['Enter', ' '].includes(e.key)) { return; } // 阻止默认行为,避免button自带点击事件重复触发 e.preventDefault(); e.stopPropagation(); // 获取当前触发按钮对应的父级li const parentItem = this.closest('.site-menu__item--has-submenu'); const isActive = parentItem.classList.contains("submenu-active"); // 先关闭所有已激活的子菜单 site_menu.querySelectorAll(".submenu-active").forEach(active => { active.classList.remove("submenu-active"); active.querySelector('button').setAttribute('aria-expanded', 'false'); }); // 切换当前菜单状态 if (!isActive) { parentItem.classList.add("submenu-active"); this.setAttribute('aria-expanded', 'true'); } else { this.setAttribute('aria-expanded', 'false'); } } // 事件绑定到button上 subButtons.forEach(btn => { btn.addEventListener("click", toggleItem, false); btn.addEventListener("keydown", toggleItem, false); }); // 点击任意位置关闭子菜单 function closeSubmenu(e) { const isClickInside = site_menu.contains(e.target); if (!isClickInside && site_menu.querySelector(".submenu-active")) { const activeItem = site_menu.querySelector(".submenu-active"); activeItem.classList.remove("submenu-active"); activeItem.querySelector('button').setAttribute('aria-expanded', 'false'); } } document.addEventListener("click", closeSubmenu, false); document.addEventListener('keydown', (event) => { if (event.key === 'Escape' && !(event.ctrlKey || event.altKey || event.shiftKey)) { const activeItem = site_menu.querySelector(".submenu-active"); if (activeItem) { activeItem.classList.remove("submenu-active"); const triggerBtn = activeItem.querySelector('button'); triggerBtn.setAttribute('aria-expanded', 'false'); // 焦点返回触发按钮,符合可访问性要求 triggerBtn.focus(); } } });
内容的提问来源于stack exchange,提问作者xoam
相关产品推荐
相关产品推荐

