汉堡菜单动画(三线变 X 折叠菜单动效源码)

CSSJS 许可:自研原创

汉堡菜单动画源码:三条线旋转交叉变成 ✕,菜单面板弹性弹出、菜单项依次滑入,支持点击外部关闭与 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 更规范

兼容性与性能

常见问题

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(缓动曲线)等属性即可,代码中有注释说明。

✍️ 作者与审核