纯 CSS 侧边抽屉菜单可通过 checkbox + ~ 选择器和 transform: translateX() 实现,需确保开关与菜单为同级兄弟元素,结构错误会导致选择器失效;滚动锁定需 JS 配合 class 控制 body 溢出,框架中推荐用状态管理替代纯 CSS 方案。

用 CSS transform 实现侧边抽屉菜单(无 JS 也能动)
纯 CSS 就能实现点击按钮拉出/收起侧边菜单,关键靠 transform: translateX() + checkbox 模拟开关状态。不需要 JS 就能响应点击,兼容性好(IE10+),且动画顺滑。
- 把菜单容器设为
position: fixed,左边界设为left: -300px(宽度 300px),初始完全隐藏 - 用一个隐藏的
<input type="checkbox" id="menu-toggle">作为状态开关 - 菜单区域用
<label for="menu-toggle"></label>关联开关,点击即触发:checked状态 - 配合
~选择器:当#menu-toggle:checked ~ .drawer时,执行transform: translateX(0) - 加
transition: transform 0.3s ease让位移有缓动效果
HTML 结构必须满足父子/兄弟关系才能用 ~ 选择器
如果结构写成嵌套或脱离兄弟链,~ 就失效。常见错误是把菜单放在 <header></header> 内部,而开关按钮在 顶层 —— 这样它们不是同级元素,无法用 ~ 关联。
- 正确结构:开关
<input>和菜单<aside class="drawer"></aside>必须是同一父容器下的兄弟节点 - 推荐把两者都放在
最外层,避免被其他组件包裹干扰 - 若必须嵌套(比如菜单在 React 组件里),就得换方案:改用
class切换 + JS 控制,或用:target配合锚点(但不支持关闭后清空 URL)
移动端点击穿透和滚动锁定怎么处理
抽屉展开时,背景内容仍可滚动、点击透传到下层,这是默认行为。要禁用,得手动干预。
- 展开时给
加overflow: hidden:用#menu-toggle:checked ~ body不行(CSS 不能向上选父级),必须 JS 或提前写好类名切换 - 更稳妥做法:用 JS 监听
change事件,在checked时加document.body.classList.add('no-scroll'),再配 CSS.no-scroll { overflow: hidden } - 菜单内部需支持滚动?给
.drawer > .content设max-height: 100vh和overflow-y: auto,避免撑开整个页面 - 别忘了加
touch-action: manipulation到按钮上,减少 iOS 点击延迟
React/Vue 项目里别硬套纯 CSS 方案
现代框架中强行用 checkbox + ~ 会破坏数据流,状态不可控,调试困难,且 SSR 下首次渲染可能闪动(服务端没状态,菜单默认展开或收起不一致)。
立即学习“前端免费学习笔记(深入)”;
- React 推荐用
useState控制isOpen,菜单加className={isOpen ? 'drawer-open' : ''} - Vue 用
v-bind:class绑定动态类名,配合transition组件做 enter/leave 动画 - 如果坚持零 JS,至少用
data-*属性标记初始状态,服务端渲染时输出对应 class,避免水合 mismatch - 注意:框架内直接操作
document.body要加useEffect/onMounted守卫,否则 SSR 报错
~ 选择器失效、body 锁定失败、iOS 滚动穿透,这几个点一漏就全白搭。


















