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

CSS多transform动画行为异常求助:需实现顶端仅Y轴线性运动

问题描述

为单个元素实现了包含rotate与translateY的多transform CSS动画,但实际表现与预期不符。期望元素顶端仅沿Y轴做线性运动,现有代码如下:

原CSS代码

.container1 {
  width: 100px;
  height: 100px;
  border: 1px solid black;
}

.stem1 {
  width: 6px;
  height: 50px;
  margin: 0 auto;
  background: #154360;
  animation: stem1-motion 5s linear forwards;
  animation-iteration-count: infinite;
}

.container2 {
  width: 100px;
  height: 150px;
  border: 1px solid black;
}

.stem2 {
  width: 6px;
  height: 50px;
  margin: 0 auto;
  background: #154360;
  animation: stem2-motion 5s linear forwards;
  animation-iteration-count: infinite;
}

.container3 {
  width: 100px;
  height: 150px;
  border: 1px solid black;
}

.stem3 {
  width: 6px;
  height: 50px;
  margin: 0 auto;
  background: #154360;
  animation: stem3-motion 5s linear forwards;
  animation-iteration-count: infinite;
}

@keyframes stem1-motion {
  0% {
    transform: rotate(0.0deg);
    transform-origin: top center;
  }
  8% {
    transform: rotate(-9.98deg);
    transform-origin: top center;
  }
  16% {
    transform: rotate(-17.69deg);
    transform-origin: top center;
  }
  25% {
    transform: rotate(-21.10deg);
    transform-origin: top center;
  }
  33% {
    transform: rotate(-18.38deg);
    transform-origin: top center;
  }
  41% {
    transform: rotate(-11.12deg);
    transform-origin: top center;
  }
  50% {
    transform: rotate(-2.52deg);
    transform-origin: top center;
  }
  58% {
    transform: rotate(9.98deg);
    transform-origin: top center;
  }
  66% {
    transform: rotate(17.69deg);
    transform-origin: top center;
  }
  75% {
    transform: rotate(21.10deg);
    transform-origin: top center;
  }
  83% {
    transform: rotate(18.38deg);
    transform-origin: top center;
  }
  91% {
    transform: rotate(11.12deg);
    transform-origin: top center;
  }
  100% {
    transform: rotate(5.05deg);
    transform-origin: top center;
  }
}

@keyframes stem2-motion {
  0% {
    transform: translateY(0.0px);
    transform-origin: top center;
  }
  8% {
    transform: translateY(5.566199398026136px);
    transform-origin: top center;
  }
  16% {
    transform: translateY(20.887794225945157px);
    transform-origin: top center;
  }
  25% {
    transform: translateY(45.0px);
    transform-origin: top center;
  }
  33% {
    transform: translateY(66.67891533457717px);
    transform-origin: top center;
  }
  41% {
    transform: translateY(82.99475664759068px);
    transform-origin: top center;
  }
  50% {
    transform: translateY(90.0px);
    transform-origin: top center;
  }
  58% {
    transform: translateY(84.43380060197387px);
    transform-origin: top center;
  }
  66% {
    transform: translateY(69.11220577405487px);
    transform-origin: top center;
  }
  75% {
    transform: translateY(45.00000000000001px);
    transform-origin: top center;
  }
  83% {
    transform: translateY(23.32108466542279px);
    transform-origin: top center;
  }
  91% {
    transform: translateY(7.005243352409316px);
    transform-origin: top center;
  }
  100% {
    transform: translateY(0.0px);
    transform-origin: top center;
  }
}

@keyframes stem3-motion {
  0% {
    transform: rotate(0.0deg) translateY(0.0px);
    transform-origin: top center;
  }
  8% {
    transform: rotate(-9.987383695374957deg) translateY(5.566199398026136px);
    transform-origin: top center;
  }
  16% {
    transform: rotate(-17.69548887689718deg) translateY(20.887794225945157px);
    transform-origin: top center;
  }
  25% {
    transform: rotate(-21.10019602409302deg) translateY(45.0px);
    transform-origin: top center;
  }
  33% {
    transform: rotate(-18.38921403145706deg) translateY(66.67891533457717px);
    transform-origin: top center;
  }
  41% {
    transform: rotate(-11.1219360330404deg) translateY(82.99475664759068px);
    transform-origin: top center;
  }
  50% {
    transform: rotate(-2.5260153474725556e-15deg) translateY(90.0px);
    transform-origin: top center;
  }
  58% {
    transform: rotate(9.987383695374957deg) translateY(84.43380060197387px);
    transform-origin: top center;
  }
  66% {
    transform: rotate(17.695488876897173deg) translateY(69.11220577405487px);
    transform-origin: top center;
  }
  75% {
    transform: rotate(21.10019602409302deg) translateY(45.00000000000001px);
    transform-origin: top center;
  }
  83% {
    transform: rotate(18.38921403145705deg) translateY(23.32108466542279px);
    transform-origin: top center;
  }
  91% {
    transform: rotate(11.121936033040393deg) translateY(7.005243352409316px);
    transform-origin: top center;
  }
  100% {
    transform: rotate(5.052030694945111e-15deg) translateY(0.0px);
    transform-origin: top center;
  }
}

原HTML代码

<div class="container1">
  <div class="stem1">

  </div>
</div>
<div class="container2">
  <div class="stem2">

  </div>
</div>
<div class="container3">
  <div class="stem3">

  </div>
</div>
问题分析

核心问题是transform函数的执行顺序:CSS中transform的多个函数是从右向左依次执行的。你当前写的rotate(...) translateY(...),实际是先执行translateY,再基于平移后的元素做rotate,这会导致元素顶端因旋转产生横向偏移,无法保持沿Y轴的线性运动。

另外,transform-origin: top center虽然设置了旋转轴心,但因为平移先执行,旋转后的顶端位置还是会偏离Y轴路径。

修正方案

最直接的解决方法是将旋转和平移动画拆分到嵌套元素中:外层元素负责Y轴方向的平移,内层元素负责绕自身顶端中心旋转。这样两个变换独立作用,外层平移保证顶端沿Y轴线性运动,内层旋转实现摆动效果,互不干扰。

以下是修正后的完整代码:

修正后的CSS代码

.container1 {
  width: 100px;
  height: 100px;
  border: 1px solid black;
}

.stem1 {
  width: 6px;
  height: 50px;
  margin: 0 auto;
  background: #154360;
  animation: stem1-motion 5s linear infinite;
}

.container2 {
  width: 100px;
  height: 150px;
  border: 1px solid black;
}

.stem2 {
  width: 6px;
  height: 50px;
  margin: 0 auto;
  background: #154360;
  animation: stem2-motion 5s linear infinite;
}

.container3 {
  width: 100px;
  height: 150px;
  border: 1px solid black;
}

/* 外层容器负责平移 */
.stem3-wrapper {
  width: 6px;
  margin: 0 auto;
  animation: stem2-motion 5s linear infinite;
}
/* 内层元素负责旋转 */
.stem3 {
  width: 100%;
  height: 50px;
  background: #154360;
  animation: stem1-motion 5s linear infinite;
  transform-origin: top center;
}

@keyframes stem1-motion {
  0% { transform: rotate(0.0deg); }
  8% { transform: rotate(-9.98deg); }
  16% { transform: rotate(-17.69deg); }
  25% { transform: rotate(-21.10deg); }
  33% { transform: rotate(-18.38deg); }
  41% { transform: rotate(-11.12deg); }
  50% { transform: rotate(-2.52deg); }
  58% { transform: rotate(9.98deg); }
  66% { transform: rotate(17.69deg); }
  75% { transform: rotate(21.10deg); }
  83% { transform: rotate(18.38deg); }
  91% { transform: rotate(11.12deg); }
  100% { transform: rotate(5.05deg); }
}

@keyframes stem2-motion {
  0% { transform: translateY(0.0px); }
  8% { transform: translateY(5.566199398026136px); }
  16% { transform: translateY(20.887794225945157px); }
  25% { transform: translateY(45.0px); }
  33% { transform: translateY(66.67891533457717px); }
  41% { transform: translateY(82.99475664759068px); }
  50% { transform: translateY(90.0px); }
  58% { transform: translateY(84.43380060197387px); }
  66% { transform: translateY(69.11220577405487px); }
  75% { transform: translateY(45.00000000000001px); }
  83% { transform: translateY(23.32108466542279px); }
  91% { transform: translateY(7.005243352409316px); }
  100% { transform: translateY(0.0px); }
}

修正后的HTML代码

<div class="container1">
  <div class="stem1"></div>
</div>
<div class="container2">
  <div class="stem2"></div>
</div>
<div class="container3">
  <div class="stem3-wrapper">
    <div class="stem3"></div>
  </div>
</div>
说明
  • 拆分后,stem3-wrapper执行原stem2-motion的Y轴平移动画,保证顶端沿Y轴线性运动;
  • stem3执行原stem1-motion的旋转动画,transform-origin: top center确保绕自身顶端旋转;
  • 两个动画使用相同的时长和缓动函数,保证同步性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 22:40:38