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
相关产品推荐
相关产品推荐

