用 checkbox + label 实现汉堡图标到叉号的平滑动画,关键在于状态控制时机与避免布局塌陷:上横线 rotate(45deg) translate(4px,4px),中横线 opacity:0,下横线 rotate(-45deg) translate(4px,-4px),统一 transition,label 加 backface-visibility:hidden 防 Safari 闪跳。

直接用 transform 和 opacity 配合 CSS 过渡就能实现汉堡图标到叉号的平滑动画,关键不在“怎么动”,而在“怎么控制状态切换时机”和“避免常见布局塌陷”。
用 checkbox + label 模拟点击开关最稳
不用 JS 也能响应点击,且天然支持键盘焦点和屏幕阅读器。很多教程用 :hover 或纯 JS 切 class,但实际项目中容易丢失可访问性或触发时机错乱。
-
<input type="checkbox" id="menu-toggle">放在 DOM 前面(隐藏但保留语义) -
<label for="menu-toggle">包裹三条横线,点击即触发 checkbox 状态翻转 - 用
#menu-toggle:checked ~ .hamburger span选择器驱动后续样式变化
三条横线的定位和旋转必须用 transform,别用 top/left
用 top/left 移动会触发重排(reflow),动画卡顿;而 transform 只触发重绘(repaint),性能好得多。叉号的形成本质是:上横线顺时针转 45°、下横线逆时针转 45°、中横线透明度归零。
- 上横线:加
transform: rotate(45deg) translate(4px, 4px) - 中横线:加
opacity: 0(不要设display: none,否则过渡失效) - 下横线:加
transform: rotate(-45deg) translate(4px, -4px) - 所有
transform动画必须统一加transition: transform 0.3s ease, opacity 0.3s ease
移动端点击区域太小?用 padding 扩展 label 而非改 span 尺寸
直接放大 span 会导致旋转后位置偏移、计算复杂。正确做法是给 label 设 padding: 12px,再用 box-sizing: border-box 保证尺寸可控。这样点击热区变大,但图标的视觉大小和旋转中心点完全不变。
立即学习“前端免费学习笔记(深入)”;
- 避免对
span设置width/height,只用height+line-height控制单条线粗细 - 所有横线用
display: block+width: 24px+height: 2px+background: currentColor - 用
margin: 4px 0控制间距,确保三条线总高度 = 2px×3 + 4px×2 = 14px,旋转时不会溢出容器
真正难的是让动画在 Safari iOS 上不闪、不跳——务必给父容器(label)加 backface-visibility: hidden,否则旋转过程中可能出现渲染撕裂。这个细节几乎没人提,但线上真会出问题。


















