grid 无法实现多级列表因其只处理直系子元素且不解析 dom 层级;正确做法是每级容器单独设 display: grid,用固定 grid-column 定位,并配合 display: none 响应式控制显隐。

直接用 grid-template-columns 配合 auto-fit 和 minmax() 无法实现真正的“多级”列表——它只管列数,不管层级关系。多级列表(如带展开/折叠的嵌套菜单、树形结构)必须靠显式层级控制 + 显式显隐切换,Grid 只负责定位,不负责逻辑。
为什么 grid-template-columns: repeat(auto-fit, ...) 不适用于多级列表
这个组合专为「同级平铺」设计,比如商品卡片、文章摘要。它会把所有子项(无论 DOM 深度)当成同一级网格项处理。如果你把二级菜单项也写成 .item 并丢进同一个 .list 容器里,Grid 会强行把它们塞进同一行轨道,完全无视父子关系。
- 常见错误:把
<ul class="submenu"></ul>直接作为.list的子元素,期望它自动缩进或换列——结果是它和一级项并排,甚至重叠 - 根本原因:
grid不解析 DOM 层级,只看直系子元素;auto-fit更是纯宽度驱动,与数据结构无关 - 正确思路:多级 = 多个独立 Grid 容器,每级一个,各自声明
display: grid
多级列表必须每级容器都设 display: grid
Grid 上下文不会继承,也不会穿透嵌套。一级菜单容器、二级弹出层、三级浮层,每个都要单独加 display: grid,否则 grid-column、grid-row 全部失效。
- 一级容器:
.menu-root { display: grid; grid-template-columns: 240px 240px 240px; } - 每个可展开项需包裹一层:
<li><div class="submenu-wrapper"><ul class="submenu" data-level="2">...</ul></div></li> - 子菜单自身也要声明:
.submenu { display: grid; },否则你写的grid-column: 2不起作用 - 漏掉任意一级的
display: grid,对应层级就会塌陷到左上角或堆叠错位
用 grid-column 固定列轨道,别用 span
grid-column: span 2 看似省事,但多级嵌套时极易失控:二级设了 span 2,三级再嵌套一层就变成 span 4,超出预设列宽,触发换行或溢出。
- 可靠做法:顶层定义固定列轨道,如
grid-template-columns: 240px 240px 240px - 一级项默认占第 1 列:
.menu-item { grid-column: 1; } - 二级菜单强制进第 2 列:
.submenu[data-level="2"] { grid-column: 2; } - 三级菜单进第 3 列:
.submenu[data-level="3"] { grid-column: 3; } - 这样位置完全可控,且不依赖 DOM 嵌套深度变化
小屏下必须用 display: none 控制子菜单显隐
仅靠改 grid-column: 1 或 visibility: hidden 不行——子菜单仍在渲染、仍占空间、影响滚动和键盘焦点流。
- 响应式断点中,对子菜单统一加:
@media (max-width: 768px) { .submenu { display: none; } } - 父容器的
overflow必须设为visible,否则子菜单会被裁剪 - 别忘了给可展开项加
position: relative,确保display: none的子菜单在隐藏时不影响布局流 - 如果用 JavaScript 动态控制显隐,记得同步切
aria-expanded和hidden属性,兼顾可访问性
真正难的不是怎么让二级菜单出现在第二列,而是怎么让它在小屏下彻底消失、不占空间、不抢焦点、不破坏滚动锚点——这些细节在 DOM 动态更新后才暴露出来,得靠 display: none + 显式层级 + 固定轨道三者配合才能稳住。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











