You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

:before和:after元素旋转中心失效问题求助

汉堡菜单转X形动画修复方案

问题描述

实现汉堡菜单转X形动画时,顶部和底部的bar旋转时会偏离中心,即使设置了transform-origin: center也无效,期望三个bar能以按钮中心为轴完成旋转切换。

原始代码

HTML

<body>
  <div id="menu-btn" onclick="toggleState(this)">
    <div id="menu-icon" class=""></div>
  </div>
</body>

CSS

:root {
  --btn-size: min(8vh, 8vw);
  --bar-height: calc(var(--btn-size) / 5);
  --margin-top: calc(var(--bar-height)*2);
  --margin-bottom: calc(var(--bar-height)*-2);
  --animation: 1s;
  --anim-half: calc(var(--animation)/2);
  --anim-func: ease-in-out;
  --btn-color: #929292;
}

body {
  height: max-content;
  width: max-content;
  margin: 5%;
}

#menu-btn {
  height: var(--btn-size);
  width: var(--btn-size);
  display: flex;
  align-items: center;
  cursor: pointer;
}

#menu-icon,
#menu-icon::before,
#menu-icon::after {
  height: var(--bar-height);
  width: var(--btn-size);
  background-color: var(--btn-color);
  position: absolute;
  transform-origin: center;
}

#menu-icon {
  transition: rotate var(--animation) var(--anim-func) 0.00s;
}

#menu-icon::before {
  transition: translate var(--anim-half) var(--anim-func) var(--anim-half), rotate var(--anim-half) var(--anim-func) 0.00s;
  content: "";
  transform: translateY(var(--margin-top));
}

#menu-icon::after {
  transition: translate var(--anim-half) var(--anim-func) var(--anim-half), rotate var(--anim-half) var(--anim-func) 0.00s;
  content: "";
  transform: translateY(var(--margin-bottom));
}

.animate #menu-icon {
  transition: rotate var(--animation) var(--anim-func) 0.00s;
  rotate: 360deg;
}

.animate #menu-icon::before {
  transition: translate var(--anim-half) var(--anim-func) 0.00s, rotate var(--anim-half) var(--anim-func) var(--anim-half);
  translate: 0px var(--margin-bottom);
  rotate: 45deg;
}

.animate #menu-icon::after {
  transition: translate var(--anim-half) var(--anim-func) 0.00s, rotate var(--anim-half) var(--anim-func) var(--anim-half);
  translate: 0px var(--margin-top);
  rotate: -45deg;
}

JavaScript

function toggleState(target) {
  target.classList.toggle("animate");
}

修复方案

问题核心是绝对定位元素缺少正确的定位参考,且transform执行顺序导致旋转中心偏离。修复步骤如下:

  • 给#menu-btn和#menu-icon添加定位属性,让伪元素的绝对定位基于按钮容器,而非整个文档
  • 用top/bottom属性替代transform: translateY设置伪元素初始位置,确保旋转中心对齐按钮中心
  • 统一设置所有bar的transform-origin为按钮中心
  • 调整动画过渡的顺序和延迟,让位置移动完成后再执行旋转

修改后的完整代码

HTML(无变化)

<body>
  <div id="menu-btn" onclick="toggleState(this)">
    <div id="menu-icon" class=""></div>
  </div>
</body>

CSS

:root {
  --btn-size: min(8vh, 8vw);
  --bar-height: calc(var(--btn-size) / 5);
  --animation: 1s;
  --anim-half: calc(var(--animation)/2);
  --anim-func: ease-in-out;
  --btn-color: #929292;
}

body {
  height: max-content;
  width: max-content;
  margin: 5%;
}

#menu-btn {
  height: var(--btn-size);
  width: var(--btn-size);
  display: flex;
  align-items: center;
  cursor: pointer;
  /* 作为按钮内部元素的定位容器 */
  position: relative;
}

#menu-icon {
  height: var(--bar-height);
  width: var(--btn-size);
  background-color: var(--btn-color);
  /* 作为伪元素的定位参考 */
  position: relative;
  transition: rotate var(--animation) var(--anim-func);
  transform-origin: center;
}

#menu-icon::before,
#menu-icon::after {
  content: "";
  height: var(--bar-height);
  width: var(--btn-size);
  background-color: var(--btn-color);
  position: absolute;
  /* 旋转中心设为按钮的中心 */
  transform-origin: 50% 50%;
  left: 0;
}

#menu-icon::before {
  top: calc(var(--bar-height) * 2);
  transition: top var(--anim-half) var(--anim-func), rotate var(--anim-half) var(--anim-func) var(--anim-half);
}

#menu-icon::after {
  bottom: calc(var(--bar-height) * 2);
  transition: bottom var(--anim-half) var(--anim-func), rotate var(--anim-half) var(--anim-func) var(--anim-half);
}

.animate #menu-icon {
  rotate: 360deg;
}

.animate #menu-icon::before {
  top: 0;
  rotate: 45deg;
  transition: top var(--anim-half) var(--anim-func) var(--anim-half), rotate var(--anim-half) var(--anim-func);
}

.animate #menu-icon::after {
  bottom: 0;
  rotate: -45deg;
  transition: bottom var(--anim-half) var(--anim-func) var(--anim-half), rotate var(--anim-half) var(--anim-func);
}

JavaScript(无变化)

function toggleState(target) {
  target.classList.toggle("animate");
}

说明

修改后,伪元素先通过top/bottom属性移动到按钮中心位置,再围绕按钮中心旋转,完美实现汉堡菜单到X形的平滑切换,不会出现偏移问题。

内容的提问来源于stack exchange,提问作者TheDudeofDC

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 05:20:56