侧拉菜单必须用transform: translateX()而非left或margin-left,因其触发GPU加速、不触发重排、不影响文档流,动画更流畅;需配合position: fixed/absolute、明确width、仅过渡transform,并设置overflow-x: hidden防滚动条。

侧拉菜单为什么用 transform: translateX() 而不是 left 或 margin-left
因为 transform 触发 GPU 加速,动画更流畅,且不触发重排(reflow),而 left 和 margin-left 会强制浏览器重新计算布局,尤其在移动端容易卡顿。另外,translateX() 不影响文档流,菜单收起时不会挤压主内容区域。
常见错误是直接对 <nav> 设置 left: -100% 并加 transition,结果页面出现横向滚动条,或点击后菜单闪一下才动——本质是没隔离 transform 的渲染上下文。
- 必须给侧栏父容器(如
<body>或一个包裹<div class="app">)设置overflow-x: hidden,否则 translate 出去的部分仍可滚动 - 侧栏自身需设
position: fixed或absolute,且width明确(如300px或80vw),不能依赖内容撑开 - transition 应写在侧栏元素上,且只过渡
transform,避免写all 0.3s导致意外属性也被缓动
如何用 checkbox + label 实现无 JS 的开关控制
纯 CSS 方案适合轻量场景,避免 DOM 操作和事件绑定的复杂性,也天然支持 SSR 和禁用 JS 的环境。核心是利用 <input type="checkbox"> 的 :checked 状态配合兄弟选择器 ~ 或相邻选择器 + 控制菜单显隐。
典型结构是把 <input id="menu-toggle"> 放在最前,<label for="menu-toggle"> 做汉堡按钮,<aside class="sidebar"> 放在 input 后面并用 input:checked ~ .sidebar 触发 translate。
立即学习“前端免费学习笔记(深入)”;
-
<input>必须有id,且<label>的for值与之严格一致,大小写敏感 - 如果 sidebar 不是 input 的后续兄弟元素(比如被其他 div 包裹了),
~就失效,此时得把 input 提到最外层容器顶部,或改用 JS - 移动端点击 label 有时会触发两次(iOS Safari 常见),可在
<input>上加ontouchstart="void(0)"防止
transform: translateX(-100%) 的基准到底是哪?
这个值的“100%”是相对于该元素自身的宽度,不是视口或父容器。所以如果 sidebar 宽度是 300px,translateX(-300px) 和 translateX(-100%) 效果一样;但如果用了 max-width: 90vw,那 -100% 就是当前实际渲染宽度,更灵活。
容易踩的坑是:菜单里放了一个 width: 100vw 的子元素,结果 translate 后右侧留白——因为子元素按视口宽铺满,但父 sidebar 只有 300px 宽,overflow 默认 visible,内容溢出。
- 侧栏内部所有子元素建议设
box-sizing: border-box,避免 padding/border 导致宽度超限 - 若需全屏遮罩(overlay),它不能是 sidebar 的子元素,而应同级存在,并用
input:checked ~ .overlay控制 opacity/visibility - 动画结束时记得加
will-change: transform(仅在需要时),但别滥用,可能引发内存占用升高
移动端 touch 滑动关闭怎么兼容 translate 动画
CSS transform 本身不响应 touchmove,要实现“手指拖拽菜单滑出/滑入”,必须用 JS 监听 touchstart/touchmove,动态设置 style.transform = translateX(${x}px),松手后根据位移阈值决定是补完动画还是回弹。
这时候 CSS 的 transition 就退居为“补动画阶段”的工具,而拖拽过程是 JS 实时更新内联样式。关键点在于:不要在拖拽中反复读取 getBoundingClientRect(),而应记录初始 touch 位置和初始 translate 值,用 delta 计算偏移。
- 监听
touchmove时加{ passive: false },否则 iOS Safari 会忽略 preventDefault(),导致页面跟着拖拽滚动 - 松手后判断
Math.abs(deltaX) > 50再决定是否关闭,50 是经验值,太小易误触,太大难触发 - 补动画阶段用
element.style.transition = 'transform 0.25s ease-out',完成后立刻清空 transition,避免影响下一次 JS 更新



















