后台菜单必须用嵌套实现语义化多级结构,禁用拼凑;正确使用aria-label、padding-inline-start缩进、flex-basis动画及:has(> .submenu)精准控制层级显隐。

用嵌套 <ul></ul> 构建语义化多级结构
后台系统菜单必须用嵌套 <ul></ul>,不能靠 <div> 拼凑。浏览器和读屏软件依赖这种结构识别父子关系,否则 Tab 键跳转错乱、NVDA 读不出层级。
<p>正确结构长这样:</p>
<pre class="brush:php;toolbar:false;"><nav aria-label="主菜单"><ul class="menu">
<li class="menu-item">
<span class="menu-toggle">系统管理</span>
<ul class="submenu">
<li><a href="/roles">角色管理</a></li>
<li><a href="/perms">权限配置</a></li>
</ul>
</li>
</ul></nav></pre>
<ul>
<li>
<code><ul></ul> 必须直接包裹 <li>,子 <ul></ul> 紧跟在父 <li> 内部,顺序不能错
<ul class="menu"></ul> 设 display: flex——会破坏列表语义,缩进和焦点顺序全乱class="submenu",方便 CSS/JS 精准控制,避免后代选择器误匹配用 :has(> .submenu) 控制展开逻辑
写 .active ul { display: block } 是最常见错误:一点开一级菜单,所有深层子菜单全弹出来。
真正隔离层级,得靠 > 和 :has() 组合:
.menu-item > .submenu { display: none; }
.menu-item:has(> .submenu) > .menu-toggle::after { content: "▼"; }
.menu-item.active > .submenu { display: block; }
-
:has(> .submenu)只匹配「直接子级含.submenu」的项,不穿透到孙子级 -
>确保.active > .submenu只影响当前下一级,不会波及更深层 - IE 不支持
:has(),可降级为手动加class="has-child",但现代后台系统基本无需兼容 IE
缩进别靠 margin-left 或 text-indent
用 margin-left 做缩进,会导致点击热区偏移;用 text-indent 只缩首行,对 inline 元素行为不稳定,且无法撑开整个菜单项背景。
统一用 padding-inline-start(兼顾 RTL)作用在 <ul></ul> 上:
.submenu { padding-inline-start: 24px; }
.submenu .submenu { padding-inline-start: 48px; }
.submenu .submenu .submenu { padding-inline-start: 72px; }
- 缩进值累加,视觉层级一目了然,且不影响 tab 键顺序或焦点框位置
- 若需支持阿拉伯语等 RTL 场景,
padding-inline-start比padding-left更可靠 - 千万别给
<li>单独设padding-left——子菜单动画时文字会“抽搐”,因为<ul></ul>高度变化没预留空间
伸缩侧边栏用 flex + max-height 动画
纯 CSS 实现伸缩,核心是让侧边栏宽度可变、内容区域自动适应,同时展开收起有过渡感。
布局上优先用 display: flex:
<div class="layout"> <aside class="sidebar">...</aside><main class="content">...</main> </div>
.layout { display: flex; min-height: 100vh; }
.sidebar { flex: 0 0 240px; transition: flex-basis 0.3s ease; }
.content { flex: 1; overflow-y: auto; }
.sidebar.collapsed { flex-basis: 60px; }
- 用
flex-basis动画比width可靠——父容器是 flex 时,width会被覆盖 - 收起时必须设
min-width: 0,否则flex-basis: 60px缩不下去 - 子菜单展开动画用
max-height(如max-height: 500px),不用height: 0——后者在 IE 和带 padding/border 的子元素中计算不准
缩进样式和动画逻辑必须解耦:缩进由 CSS 结构决定,动画只控制显隐和尺寸,否则折叠后层级错位、焦点丢失的问题会反复出现。











