css变量通过dom级联传递,子菜单需只读父级--is-open值;动画用transform配合will-change按需启用;ie用@supports降级至class切换。

抽屉菜单层级嵌套时,CSS变量怎么传下去
子菜单动画必须依赖父级展开状态,但 CSS 变量默认不继承,:host 或 inherit 都不管用。真正能穿透层级的是自定义属性在 DOM 树中的**级联行为**:只要父元素设了 --is-open,子元素直接 var(--is-open) 就能读到,前提是它没被中间某层重写。
常见错误是每个菜单都独立声明 --is-open: 0,结果子菜单永远拿不到父级的 1。正确做法是只在触发点(比如按钮)或最外层容器设初始值,子菜单只读不设。
- 根容器加
style="--is-open: 0",点击时用 JS 切换为1 - 所有子菜单用
transition: transform .3s cubic-bezier(.25,.46,.45,.94),配合transform: translateX(calc(var(--is-open) * 100%)) - 避免在
.submenu规则里写--is-open: 0—— 这会覆盖上级值
动画卡顿?检查 transform 和 will-change 的组合
多层抽屉叠加时,浏览器容易把每层都当普通重绘处理,尤其在移动端。单纯靠 transform 不够,得告诉浏览器“这东西要动”。但 will-change: transform 不能乱加,否则内存暴涨。
只对当前正在展开/收起的菜单加,且 JS 控制:展开前设 style="will-change: transform",动画结束立刻移除。子菜单要等父级 transition 结束后再触发自己的 will-change,否则父子同时抢 GPU 资源。
- 用
getComputedStyle(el).transitionDuration拿到时长,setTimeout清除will-change - 别给
*[class*="drawer"]全局加will-change—— Chrome 会为每个元素分配图层 - 如果子菜单用
opacity配合transform,记得把opacity也放进will-change列表
JS 控制 CSS 变量时,避免频繁重排
每次鼠标 hover 就调 el.style.setProperty('--is-open', '1') 看似简单,但若菜单有 5 层,每层都 setProperty,浏览器会同步计算样式树,卡顿明显。
真正轻量的做法是:只操作最外层容器的变量,让所有子菜单靠级联响应;JS 只负责开关这个顶层变量,其余全由 CSS 完成。
- 用
document.documentElement.style.setProperty('--drawer-root-open', value)统一控制 - 子菜单选择器写成
[data-level="2"] { transform: translateX(calc(var(--drawer-root-open) * 100%)); } - 绝对不要在循环里对多个元素分别 setProperty —— 即使它们变量名不同
IE 不支持 CSS 变量?降级方案别硬套
IE11 完全不识别 var(--x),但强行用 JS 注入 style 标签或改 class 名做 fallback,会导致逻辑分裂、维护困难。更实际的方案是:用 @supports (--a: 0) 区分环境,IE 下直接走传统 class 切换 + CSS 动画。
重点不是“怎么让 IE 也用变量”,而是“怎么让现代浏览器用变量,IE 自动退到可靠路径”。两者 CSS 规则完全隔离,互不影响。
- 现代写法:
@supports (--foo: 0) { .drawer { transform: translateX(calc(var(--is-open) * 100%)); } } - IE 写法:
.drawer.is-open { transform: translateX(100%); transition: transform .3s; } - JS 里判断
typeof CSS !== 'undefined' && CSS.supports('--a', 0)再决定用哪套逻辑
多层级抽屉最难的不是动画本身,而是变量作用域和渲染性能的耦合 —— 父子菜单谁该设值、谁只读值、何时释放 GPU 图层,这些细节错一点,滑动就发涩。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











