不能用visibility: hidden或opacity: 0控制子菜单显隐,因其不释放布局空间、不阻断键盘焦点,违反WCAG 2.1可访问性标准;子菜单需逐级显式设display: grid并用display: none做响应式隐藏。

不能用 visibility: hidden 或 opacity: 0 控制子菜单显隐——它们不释放布局空间、不阻断键盘焦点,可访问性直接断裂。
为什么只给外层设 display: grid,子菜单就堆在左上角
Grid 上下文不会穿透 DOM 层级。父容器设了 display: grid,只有它的直系子元素成为网格项;.submenu 如果只是 li 的后代(比如 li > ul.submenu),它根本不在该网格中,grid-column: 2 这类规则完全无效。
常见错误写法:.sidebar { display: grid; },然后指望 .submenu li 响应列定位。
正确做法是逐级显式声明:
立即学习“前端免费学习笔记(深入)”;
-
.sidebar设display: grid和grid-template-columns: 240px 240px 240px - 每个可展开项需包裹一层
.submenu-wrapper,并设display: grid -
.submenu自身也必须设display: grid,否则无法解析grid-column
grid-column: span 2 为什么一嵌套就错位
span 表达的是“跨多少列”,但嵌套层级一变,实际跨度会指数级放大:二级菜单设 span 2,三级再套一层,子项就变成 span 4,超出容器宽度后触发换行或溢出,视觉上就是菜单断开、压住下方内容。
更稳的方案是固定列轨道 + 显式线号定位:
- 顶层定义三列:
grid-template-columns: 240px 240px 240px - 一级菜单项默认占第 1 列:
grid-column: 1 - 二级菜单强制进第 2 列:
.submenu[data-level="2"] { grid-column: 2; } - 三级菜单进第 3 列:
.submenu[data-level="3"] { grid-column: 3; }
小屏下用 display: none 切换,而不是改 grid-column
移动端如果只把 .submenu 的 grid-column 改成 1,它仍在渲染流中:占用空间、影响滚动高度、屏幕阅读器可读、Tab 键仍聚焦到隐藏项——这违反 WCAG 2.1。
正确响应式逻辑:
- 在
@media (max-width: 767px)中统一设:.submenu { display: none; } - JS 展开时,仅给当前路径上的那一级加
.submenu.active { display: grid; } - 同步清除同级其他
.submenu的active类,避免多级同时显示 - 别用
opacity: 0+pointer-events: none替代——它不解决焦点和语义问题
父容器漏设 overflow: visible 会导致子菜单被裁剪
子菜单横向铺开(比如从第 1 列伸到第 2 列)时,如果父容器(如 .sidebar)没设 overflow: visible,浏览器默认按 auto 或 hidden 处理,结果就是右边一半被切掉。
这个点极易被忽略,尤其当侧边栏本身是 flex 子项时:
-
.sidebar必须加:overflow: visible - 若
.sidebar是 flex 容器的子项,还要确认其父 flex 容器没设overflow: hidden - 别指望靠
z-index补救——裁剪发生在布局阶段,不是层叠顺序问题
真正难的不是算对 grid-column 的值,而是确保每一级容器都“知道自己是个网格”,且每一级都主动参与显隐控制——漏掉任意一层 display: grid 或任意一处 display: none,菜单就会在某个设备或交互路径上突然失效。


















