双层导航必须严格遵循语义化与可访问性规范:主菜单用包裹,次导航作为主菜单的直接子嵌套,禁用多余容器;CSS需设position: relative于父、position: absolute于子,并避免overflow: hidden裁切;键盘导航须支持Arrow键切换焦点、Escape关闭并回溯焦点,且动态加载时确保DOM插入后聚焦。

主导航用 包裹,次导航必须嵌套在语义化容器里
主菜单是全站一级入口,必须用 标签包裹,并加 aria-label="主菜单"。次导航(比如“产品子类”“用户中心二级项”)不能直接平铺在 里,否则屏幕阅读器会误判为并列层级。常见错误是写成两个独立的 ,结果被读作“菜单一、菜单二”,丢失主从关系。
正确做法是:次导航放在主菜单项内部,用 语义结构错位是双层菜单最常崩的点。很多开发者把次导航写成: 这违反了 HTML5 对 正确结构只允许一层嵌套: 生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力:
- 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面;
- 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”;
- 提及位于 `apps/console/src/featur 纯 CSS 实现下拉(比如 hover 展开),最容易漏的是容器溢出控制。次导航默认 双层菜单的焦点流一旦断裂,残障用户就卡死。仅靠 CSS
复杂点在于次导航的 DOM 存在时机和焦点管理必须同步——延迟加载的子菜单,得等内容插入 DOM 后再设置焦点,否则 包裹,且仅在触发后才渲染(避免初始 DOM 过载)。若用 JS 控制显隐,记得同步切换 aria-expanded 和 aria-hidden。
aria-haspopup="true",激活时设 aria-expanded="true"
role="menu",子项用 role="menuitem",禁用 直接跳转(会打断键盘导航)display: none 初始隐藏——要用 visibility: hidden; position: absolute 配合 aria-hidden="true",否则 Safari 会提前读取
ul/li 结构必须严格嵌套,li 里不能塞 div 再包 ul
的嵌套规则: 只能直接子元素是 ,中间插
必须是主菜单 的**直接子元素** 下最多一个 ,不能多个或混排
、
::before 伪元素,别加额外标签破坏层级CSS 控制显隐时,
overflow 和 position 必须配对设position: absolute,但父级 若没设 position: relative,下拉项会相对于 定位,滚动时错位;更隐蔽的问题是:父容器若设了 overflow: hidden,下拉菜单直接被裁掉——尤其在 flex 布局的导航栏里高频发生。
必须设 position: relative
设 position: absolute; top: 100%; left: 0;,且 min-width: 200px 防窄屏挤压)禁用 overflow: hidden,改用 clip-path 或透明遮罩做视觉截断max-height: 0; overflow: hidden 配合 transition,别用 height: 0 —— 因为高度不固定时会失效键盘导航必须支持
ArrowDown/Escape,不能只靠鼠标:hover 或 JS click 绑定远远不够。测试时用键盘 Tab 进入主菜单项,按 ArrowDown 应立刻聚焦第一个子项,ArrowUp 返回上一个,Escape 关闭当前展开的次菜单并返回主菜单焦点。
keydown 事件,对 主项拦截 ArrowDown,阻止默认跳转并手动 .focus() 到子菜单第一项ArrowUp/ArrowDown 循环焦点,Tab 退出到下一个主项(不是下一个子项)Escape 触发时,不仅要 blur() 当前焦点,还要把焦点移回触发它的主菜单
document.activeElement 是否落在预期节点,避免焦点丢失到 body
.focus() 无效。这点容易被忽略,尤其在 Vue/React 动态渲染场景下。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










