嵌套ul必须是父li的直接子元素,不可包裹在div中;否则DOM层级断裂,导致屏幕阅读器跳过、键盘导航失效、:hover异常及Safari兼容问题。

嵌套 ul 必须是直接子元素,不能包在 div 里
浏览器和屏幕阅读器只认 DOM 层级关系,不是靠 CSS 视觉位置。如果你写成:<li>
<a>Products</a><div><ul><li>Laptops</li></ul></div>
</li>,那二级菜单在 NVDA 或 VoiceOver 下大概率被跳过,Tab 键也进不去。
正确结构只能是:<li>
<a href="#" aria-haspopup="menu" aria-expanded="false">Products</a><ul role="menu"><li role="none"><a role="menuitem">Laptops</a></li></ul>
</li>
- 每一级
ul必须紧挨着它的父li,中间不能插div、span或其他包裹容器 -
aria-haspopup的值必须是"menu",写成"true"是 W3C 已废弃的用法 - 键盘用户依赖这个嵌套关系来判断“按 → 键是否该进入子菜单”,DOM 断了,逻辑就断了
:hover 在三级菜单失效,大概率是 position 没配对
二级 ul 用了 position: absolute 后脱离文档流,如果它的父 li 没设 position: relative,浏览器会向上找最近的有定位的祖先——结果三级菜单可能飞到页面左上角,鼠标悬停区域和实际 DOM 位置错开几十像素。
- 每级可展开的
li都必须加position: relative - 三级菜单不要用
margin-left: 100%推开,改用left: 100%; top: 0; - 避免用
display: none+:hover控制显隐——screen reader 会彻底忽略该节点;换成visibility: hidden+aria-hidden="true"
移动端不用 JS 也能做下拉,但得用 checkbox + :checked
纯 CSS 实现移动端菜单开关,比监听 click 更可靠:JS 加载失败、被拦截、或用户禁用时,菜单依然可用。
实现 Markdown↔ HTML 互转,支持导出 PDF,用于用户请求的文档格式转换。
立即学习“前端免费学习笔记(深入)”;
- HTML 中放一个隐藏
<input type="checkbox" id="menu-toggle">和对应<label for="menu-toggle">☰</label> - CSS 写
#menu-toggle:checked ~ nav ul { display: block; },注意选择器顺序不能反 - 必须加
position: absolute或top: 100%,否则下拉时页面会跳动(因为display: block会撑开布局) - 别忘了
<meta name="viewport" content="width=device-width, initial-scale=1">,否则媒体查询不生效
Safari 对 a:hover 有隐藏限制,基础样式必须显式声明
Safari(尤其 iOS)默认只允许 :hover 改变 color,其他如 background-color、transform、border 全部被忽略——除非你提前定义了 a:link 和 a:visited 的基础样式。
- 统一加:
a:link, a:visited { color: #333; text-decoration: none; } -
hover效果写在a上,不是li;否则点击热区极小,只响应文字部分 - 所有导航链接必须设
display: block或inline-block,不然悬停区域和视觉范围不一致
position 一对不上,键盘用户就进不去第二层,屏幕阅读器就念不出子项,Safari 就没反馈——这些点不手动验证,光看页面“能动”就上线,等于把可访问性关上了门。


















