animation-fill-mode 详细演示

理解"延迟期间"和四种填充模式的区别

什么是 animation-fill-mode?

animation-fill-mode 控制动画开始前和结束后元素的状态。它决定了元素在动画的"延迟期间"和"结束后"应该显示什么样式。

💡 什么是"延迟期间"?

当你设置 animation-delay: 2s 时,动画不会立即开始,而是等待 2 秒。这 2 秒就是"延迟期间"。

下面的演示中,所有动画都有 2 秒延迟。点击按钮后,仔细观察前 2 秒方块的位置和颜色!

四种填充模式

  • none - 默认值,延迟期间和结束后都不应用动画样式
  • forwards - 动画结束后保持最后一帧的状态(最常用!)
  • backwards - 延迟期间应用第一帧样式
  • both - 结合 backwards 和 forwards 的效果

backwards 的作用对比

动画:从左侧(红色)滑到中间(绿色),有 2 秒延迟

❌ none(默认)

中间
点击后:
• 0-2秒:方块在中间(绿色)等待
• 2秒时:突然跳到左边(红色)
• 2-3.5秒:从左边滑到中间
• 3.5秒后:回到中间(绿色)
.box {
  animation: slideFromLeft 1.5s ease-out 2s 1 none;
  /* 延迟期间保持原始状态 */
}

✅ backwards

中间
点击后:
立即:方块跳到左边(红色)
• 0-2秒:在左边等待
• 2-3.5秒:从左边滑到中间
• 3.5秒后:回到中间(绿色)
.box {
  animation: slideFromLeft 1.5s ease-out 2s 1 backwards;
  /* 延迟期间立即应用第一帧 */
}

🎯 关键区别

none: 延迟期间保持原始状态(中间),动画开始时才跳到起始位置(左边)

backwards: 点击后立即跳到起始位置(左边),然后在那里等待延迟结束

forwards 的作用对比

动画:从中间(绿色)滑到右边(橙色半透明),有 2 秒延迟

❌ none(默认)

中间
点击后:
• 0-2秒:在中间(绿色)等待
• 2-3.5秒:滑到右边(橙色半透明)
• 3.5秒后:回到中间(绿色)
.box {
  animation: slideToRight 1.5s ease-out 2s 1 none;
  /* 动画结束后回到原始状态 */
}

✅ forwards

中间
点击后:
• 0-2秒:在中间(绿色)等待
• 2-3.5秒:滑到右边(橙色半透明)
• 3.5秒后:停在右边(橙色半透明)
.box {
  animation: slideToRight 1.5s ease-out 2s 1 forwards;
  /* 动画结束后保持最后一帧 */
}

🎯 关键区别

none: 动画结束后,元素"闪回"到原始状态(中间,绿色)

forwards: 动画结束后,元素保持在最后一帧的状态(右边,橙色半透明)

both = backwards + forwards

动画:从左侧(红色)滑到右边(橙色半透明),有 2 秒延迟

both(完美组合)

中间
点击后:
立即:跳到左边(红色)- backwards
• 0-2秒:在左边等待
• 2-3.5秒:从左边滑到右边
• 3.5秒后:停在右边(橙色半透明) - forwards
@keyframes slideLeftToRight {
  from {
    transform: translate(-250%, -50%);
    background: var(--error);
  }
  to {
    transform: translate(150%, -50%);
    background: var(--warning);
    opacity: 0.3;
  }
}

.box {
  animation: slideLeftToRight 1.5s ease-out 2s 1 both;
}

完整对比表格

none:
延迟期间:原始状态 | 结束后:原始状态
backwards:
延迟期间:第一帧 ✨ | 结束后:原始状态
forwards:
延迟期间:原始状态 | 结束后:最后一帧 ✨
both:
延迟期间:第一帧 ✨ | 结束后:最后一帧 ✨
完整代码示例
/* 动画定义 */
@keyframes slideFromLeft {
  from {
    transform: translate(-250%, -50%); /* 在左边 */
    background: #ef4444; /* 红色 */
  }
  to {
    transform: translate(-50%, -50%); /* 在中间 */
    background: #10b981; /* 绿色 */
  }
}

/* 应用动画 */
.box {
  animation: slideFromLeft 1.5s ease-out 2s 1 backwards;
  /* 动画名 时长 缓动 延迟 次数 填充模式 */
}

详细语法说明

/* 假设动画定义:从透明到不透明 */
@keyframes fadeOut {
  from { opacity: 0.2; } /* 第一帧:透明 */
  to { opacity: 1; } /* 最后一帧:不透明 */
}

/* 元素原始状态:不透明 */
.box {
  opacity: 1;
}

/* none: 延迟期间保持原始状态,结束后回到原始状态 */
.none {
  animation: fadeOut 1s linear 2s 1 none;
  /* 延迟 2 秒期间:opacity: 1(原始)
     动画播放:opacity: 0.2 → 1
     动画结束后:opacity: 1(原始)*/
}

/* backwards: 延迟期间立即应用第一帧 */
.backwards {
  animation: fadeOut 1s linear 2s 1 backwards;
  /* 延迟 2 秒期间:opacity: 0.2(第一帧!)
     动画播放:opacity: 0.2 → 1
     动画结束后:opacity: 1(原始)*/
}

/* forwards: 结束后保持最后一帧 */
.forwards {
  animation: fadeOut 1s linear 2s 1 forwards;
  /* 延迟 2 秒期间:opacity: 1(原始)
     动画播放:opacity: 0.2 → 1
     动画结束后:opacity: 1(最后一帧!)*/
}

/* both: 结合 backwards 和 forwards */
.both {
  animation: fadeOut 1s linear 2s 1 both;
  /* 延迟 2 秒期间:opacity: 0.2(第一帧!)
     动画播放:opacity: 0.2 → 1
     动画结束后:opacity: 1(最后一帧!)*/
}

总结与最佳实践

📝 四种模式总结

  • none: 延迟期间和结束后都用原始样式
  • forwards: 结束后保持最后一帧(最常用!)
  • backwards: 延迟期间应用第一帧
  • both: 延迟期间用第一帧 + 结束后用最后一帧

💡 实际应用建议

forwards 最常用,可以让元素在动画结束后保持最终状态,避免"闪回"到初始状态。

backwards 在有延迟的动画中很有用,可以让元素在延迟期间就显示动画的起始状态,避免突然跳变。

both 适合既有延迟又需要保持结束状态的场景,是 backwards 和 forwards 的组合。