汉堡菜单动画(三线变 X 折叠菜单动效源码)
汉堡菜单动画源码:三条线旋转交叉变成 ✕,菜单面板弹性弹出、菜单项依次滑入,支持点击外部关闭与 aria 状态同步,原生 JS 零依赖,移动端导航首选。
效果演示(真实可交互)
汉堡菜单是移动端导航的事实标准,而「三线变 ✕」的形变动画是其中最经典的微交互。演示区右上角是一个白色圆角按钮:点击后三条横线中上下两条分别向内外旋转 45 度、中间一条透明消失,三线合一变成关闭图标,同时按钮底色变为主题蓝;右侧弹出下拉菜单,五个菜单项从右向左依次滑入,带 0.05 秒的错峰延迟,视觉上像多米诺骨牌。再次点击按钮或点击任意菜单项、点击页面空白处,菜单收起、三线复原。按钮的 aria-expanded 状态全程同步,读屏与键盘用户都能正确感知。菜单项使用 emoji 图标加文字的组合,既生动又无需额外图标库;菜单面板为绝对定位,展开后悬浮在内容之上,适合导航栏右上角的场景。收起时菜单直接 hidden,不占布局、不挡点击,交互逻辑干净利落。形变动画时长与菜单弹出节奏应当协调:按钮形变约 0.35 秒、菜单项依次滑入总时长约 0.3 秒,两者几乎同时收尾,视觉上浑然一体,不会出现「线已合拢菜单才弹出」的脱节。
点击右上角汉堡按钮:三条线变成 ✕,菜单项依次滑入
完整代码
HTML:按钮用三个 <span> 画线,菜单用 hidden 属性控制显隐:
<nav class="mh-nav">
<button class="mh-burger" id="mhBurger" aria-expanded="false" aria-controls="mhMenu">
<span class="mh-line"></span>
<span class="mh-line"></span>
<span class="mh-line"></span>
</button>
<div class="mh-menu" id="mhMenu" hidden>
<a href="#home">🏠 首页</a>
<a href="#docs">📚 文档</a>
<a href="#components">🧩 组件</a>
</div>
</nav>
CSS:三线变 ✕ 的核心是「上下两条旋转 45°、中间淡出」:
.mh-burger { display: flex; flex-direction: column; justify-content: center; gap: 5px; }
.mh-line {
display: block; width: 22px; height: 2.5px; margin: 0 auto; background: #33406b;
transition: transform .35s cubic-bezier(.34,1.3,.64,1), opacity .2s ease;
}
/* 展开态:gap 5px + 线高 2.5px → 位移 7.5px 恰好让两条线十字相交 */
.mh-burger.mh-open .mh-line:nth-child(1) { transform: translateY(7.5px) rotate(45deg); }
.mh-burger.mh-open .mh-line:nth-child(2) { opacity: 0; transform: scaleX(0); }
.mh-burger.mh-open .mh-line:nth-child(3) { transform: translateY(-7.5px) rotate(-45deg); }
菜单面板弹性弹出 + 菜单项依次滑入:
.mh-menu {
position: absolute; top: calc(100% + 14px); right: 0; min-width: 180px;
background: #fff; border-radius: 14px; padding: 8px;
transform-origin: top right;
animation: mh-pop .3s cubic-bezier(.34,1.3,.64,1);
}
@keyframes mh-pop { from { opacity: 0; transform: scale(.85) translateY(-8px); } }
.mh-menu a { opacity: 0; animation: mh-item .35s cubic-bezier(.34,1.3,.64,1) forwards; }
.mh-menu a:nth-child(2) { animation-delay: .05s; } /* 错峰 50ms */
.mh-menu a:nth-child(3) { animation-delay: .1s; }
@keyframes mh-item { from { opacity: 0; transform: translateX(14px); } to { opacity: 1; transform: translateX(0); } }
原生 JS:开合状态机 + 点击外部关闭:
const burger = document.getElementById('mhBurger');
const menu = document.getElementById('mhMenu');
let open = false;
function setOpen(v) {
open = v;
burger.classList.toggle('mh-open', open);
menu.hidden = !open;
burger.setAttribute('aria-expanded', String(open));
}
burger.addEventListener('click', () => setOpen(!open));
menu.querySelectorAll('a').forEach((a) => a.addEventListener('click', () => setOpen(false)));
document.addEventListener('click', (e) => {
if (open && !e.target.closest('.mh-nav')) setOpen(false);
});
参数说明
| 参数 | 默认值 | 说明 |
|---|---|---|
| 形变位移 | translateY(7.5px) | 等于「gap 5px + 线高 2.5px」,改间距需同步换算 |
| 旋转角度 | ±45deg | 两条线垂直交叉的标准角度 |
| 形变缓动 | cubic-bezier(.34,1.3,.64,1) | 过冲弹跳让形变更有弹性 |
| 菜单项错峰 | animation-delay: 50ms | 依次递增,制造多米诺入场 |
| 显隐方式 | hidden 属性 | 收起时彻底移出无障碍树,比 opacity 更规范 |
兼容性与性能
- 原生 JS + CSS,零依赖;动画全部走 transform 与 opacity(合成器属性),60fps 流畅
hidden属性所有浏览器原生支持,收起状态不占位、不可聚焦,无障碍表现最佳aria-expanded+aria-controls与按钮状态全程同步,键盘用户按 Enter/Space 即可开关- 点击外部关闭监听在
document上,用closest('.mh-nav')排除内部点击,多实例互不干扰 - 外部点击关闭因此天然支持多实例:页面里同时存在多个汉堡菜单也不会相互误关。若菜单内容很多,可给
.mh-menu追加max-height与overflow-y: auto,长列表也能流畅滚动
常见问题
Q: 三条线交叉后不是标准的 ✕? 位移必须是「gap + 线高」,例如 gap 5、线高 2.5 时位移 7.5px;改了 gap 或线高都要重新计算,否则中心点偏移。
Q: 菜单在窄屏溢出? 把 .mh-menu 改为 left: 0; right: auto 或 width: 100vw 对齐屏幕边缘,并配合 max-height + overflow-y: auto 防止超高滚动。
Q: 想让菜单出现时也带动画,收起时直接消失? 收起时给 .mh-menu 加 .mh-closing 类播放反向动画(animation 反向播放即可),监听 animationend 后再设置 hidden。
Q: 可以商用吗? 可以。本组件为粤喵自研原创代码,免费商用无需署名。
许可与来源
- 许可证:自研原创 —— 粤喵自研原创,可免费用于个人与商业项目,无需署名。查看来源公示与许可清单
- 来源:粤喵团队原创自研(从效果思路到代码实现均为独立完成,未直接复制第三方代码)
- 首次发布:2026-09-01 · 最近更新:2026-09-01
- 修改日志:2026-09-01 首次发布;2026-09-13 补充许可证与来源标注、复制按钮说明与法务页入口
- 纠错:联系页面 / min@cactus.asia,2 个工作日内核实处理
常见问题
这个组件可以商用吗?
可以。本组件为粤喵自研原创,可免费用于个人和商业项目,无需署名。
浏览器兼容性如何?
支持所有现代浏览器(Chrome / Firefox / Safari / Edge 最新版本)。旧版 IE 不支持 CSS 动画相关特性。
怎么修改动画参数?
直接调整 CSS 中的 animation-duration(时长)、animation-timing-function(缓动曲线)等属性即可,代码中有注释说明。