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

为何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动画对每个属性独立处理关键帧逻辑,具体细节如下:

  1. 属性独立插值规则
    CSS动画会为每个被动画的属性单独计算关键帧:
  • 如果某个属性在部分关键帧中未被声明,浏览器会自动为该属性补全0%和100%的关键帧,值为元素的初始样式值。
  • 然后在已声明的关键帧之间进行平滑插值。
  1. 初始代码的问题
    对于初始代码中的@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%),粉色圆点自然无法和红色圆点重合。

  1. 修正代码的作用
    当你在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 00:07:01