为何CSS动画中后关键帧的transform属性提前生效?
问题:CSS动画中为何必须显式声明
transform: translate(0%,0%)才能让元素正确居中? 我想通过CSS动画的translate属性,让#d1内的粉色圆点和父元素#dn内的红色圆点重合,动画分三个阶段:
- 0%时
#d1在左上角(top:0%;left:0%) - 50%时移动到
top:50%;left:50%位置 - 80%时通过
transform:translate(-50%,-50%)实现居中
但使用以下初始代码时动画不符合预期:
@keyframes example{ 0%{ top: 0%; left:0%; } 50%{top: 50%; left:50%; } 80%{ transform: translate(-50%, -50%);} }
只有在0%和50%关键帧中添加transform: translate(0%, 0%);,同时在80%关键帧显式声明top:50%;left:50%;,才能达到预期效果,这是为什么?
附完整可运行代码:
#dn{ width: 50vw; height: 40vh; background-color: #15badb; border: 3px solid #000; display: flex; justify-content: center; align-items: center; position: relative; } .dot{ width: 10px; height: 10px; background-color: #9e1818; border: 1px solid black; border-radius: 50%; transition: border-radius 5s; } #d1{ width: 20%; height: 20%; background-color: rgba(255,255, 233,0); border: 1px solid #000; position: absolute; top: 0%; left: 0%; display: flex; justify-content: center; align-items: center; animation-name: example; animation-duration: 18s; animation-delay: 2s; } @keyframes example{ 0%{ top: 0%; left:0%; transform: translate(0%, 0%);} 50%{top: 50%; left:50%; transform: translate(0%, 0%);} 80%{top: 50%; left:50%; transform: translate(-50%, -50%);} } #d1 .dot{ background-color: #f07fba; }
<div id="dn"> <div id="d1"> <div class="dot"></div> </div> <div class="dot"></div> </div>
原因分析
核心问题在于CSS动画对每个属性独立处理关键帧逻辑,具体细节如下:
- 属性独立插值规则
CSS动画会为每个被动画的属性单独计算关键帧:
- 如果某个属性在部分关键帧中未被声明,浏览器会自动为该属性补全
0%和100%的关键帧,值为元素的初始样式值。 - 然后在已声明的关键帧之间进行平滑插值。
- 初始代码的问题
对于初始代码中的@keyframes example:
top/left属性:仅在0%和50%声明了值,浏览器会自动补全100%关键帧的值为元素初始值0%。因此top/left的动画逻辑是:0%→50%从0%升到50%,50%→100%从50%降回0%。在80%时,top/left已经降到了20%(而非预期的50%)。transform属性:仅在80%声明了值,浏览器会自动补全0%、50%、100%关键帧的值为初始值none。因此transform的动画逻辑是:0%→50%保持none,50%→80%从none过渡到translate(-50%,-50%),80%→100%回到none。
两者叠加后,80%时元素的实际位置是top:20%;left:20%;transform:translate(-50%,-50%),粉色圆点自然无法和红色圆点重合。
- 修正代码的作用
当你在0%、50%显式声明transform: translate(0%,0%),并在80%显式声明top:50%;left:50%后:
top/left属性:关键帧变为0%(0%)、50%(50%)、80%(50%)、100%(0%)。50%→80%期间top/left保持50%不变,80%时仍处于父元素50%位置。transform属性:关键帧变为0%(translate(0,0))、50%(translate(0,0))、80%(translate(-50%,-50%))、100%(none)。50%→80%期间从无偏移过渡到自身中心偏移,最终让#d1的中心(即粉色圆点位置)和父元素50%位置重合。
这样就完全符合预期的动画逻辑了。
内容的提问来源于stack exchange,提问作者Coderey123
相关产品推荐
相关产品推荐

