语义正确、可访问的纵向折叠菜单需严格遵循HTML父子嵌套结构,子菜单必须直接嵌套在触发它的内;CSS避免破坏列表流和聚焦逻辑;JS应使用事件委托并确保键盘与读屏支持。

直接用 嵌套 就能做出语义正确、可访问性好、浏览器原生支持键盘导航的纵向折叠菜单——但多数人栽在结构错位、CSS 选择器误配、或 JS 事件绑定方式上。
HTML 结构必须严格遵循父子嵌套顺序
子菜单 顶层 直接给每个 仅靠鼠标点击展开的菜单,在 WCAG 2.1 和国内《信息技术 互联网内容无障碍可访问性指南》下属于不合格。用户按 Tab 键进入菜单项后,必须能用空格/回车展开,用方向键上下移动,用 Esc 收起当前展开项。 真正难的不是让菜单动起来,而是让它在盲人用读屏软件、工程师用键盘、手机用户单手操作时,都表现一致。结构松散、CSS 滥用、JS 直接操作 DOM,三者任一出问题,折叠菜单就从便利功能变成可访问性障碍。 必须紧跟在触发它的 内部,不能用 :has() 失效。
(子菜单脱离父 )(class="nested",避免用 ul ul ul 这类宽泛选择器污染样式CSS 控制显示/隐藏时别用 display: flex 破坏列表流
如果设了 display: flex 或 display: grid,会切断浏览器对列表项顺序和缩进的默认处理,导致 Tab 键焦点跳跃异常、list-style 失效、打印样式错乱。
display: block(默认值),用 margin 或 padding 控制间距.nested { display: none; },不要写成 visibility: hidden(仍占空间)或 opacity: 0(无法键盘聚焦)max-height + overflow: hidden 替代纯 display 切换,实现平滑收放动画.menu-item.active > .toggle::before { content: "▼"; } 这类精准子选择器,避免后代选择器误改其他层级JavaScript 绑定 click 事件优先用事件委托
绑 onclick 属性或循环 addEventListener,在动态增删菜单时容易漏绑、重复绑、内存泄漏。事件委托一次注册,一劳永逸。
的 click,用 e.target.matches('.menu-item > .toggle') 判断是否点中展开按钮.nested:用 e.target.closest('.menu-item').querySelector('.nested')
innerHTML 重绘整个菜单树——会丢失焦点、清空表单输入、触发多次重排),记得在 e.preventDefault() 前判断是否点击的是展开按钮,否则禁用跳转键盘交互和可访问性不是加分项,是硬性要求
要有 tabindex="0" 才能被键盘聚焦( 默认可聚焦,但 不行)role="button" 和 aria-expanded="false",JS 切换时同步更新该属性role="group",并用 aria-labelledby 关联父项 ID:hover 实现展开——触屏设备无 hover,且对键盘用户无效
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











