先记住这个答案
@keyframes 规则里,from 是 0% 的别名,to 是 100% 的别名,写哪个都行。两个关键帧之间的样式由浏览器根据 animation-timing-function 自动插值计算。如果你只定义了中间的百分比而没写 0% 和 100%,浏览器会用元素自身的计算样式来补全起点和终点。
from等于0%,to等于100%- 相邻关键帧之间浏览器自动插值
- 省略
0%或100%时用元素当前样式补全 - 同一百分比出现多次,后面的覆盖前面的
from 和 to 与百分比的等价关系
from 和 0% 完全等价,to 和 100% 完全等价,混着写也没问题。下面两种写法效果一样。
/* 写法一:用 from/to */
@keyframes slide {
from { transform: translateX(0); }
to { transform: translateX(200px); }
}
/* 写法二:用百分比 */
@keyframes slide {
0% { transform: translateX(0); }
100% { transform: translateX(200px); }
}实际项目里,如果只有起点和终点两帧,用 from 和 to 更简洁。需要在中间加关键帧时,用百分比更直观,比如 0%、50%、100% 三帧的动画。
多个关键帧和插值机制
可以定义任意数量的百分比关键帧,浏览器在每两个相邻帧之间做平滑插值。
@keyframes bounce {
0% { transform: translateY(0); }
40% { transform: translateY(-60px); }
60% { transform: translateY(-30px); }
100% { transform: translateY(0); }
}
.ball {
animation: bounce 1s ease-in-out infinite;
}0% 到 40% 之间,translateY 从 0 平滑过渡到 -60px。40% 到 60% 之间,从 -60px 回到 -30px。60% 到 100% 再回到 0。每一段的过渡速度由 animation-timing-function 控制。
同一个百分比位置可以写多个属性,也可以用逗号把多个百分比合并到一个块里:0%, 100% { opacity: 1; } 表示起点和终点都是完全不透明。
省略起点或终点时的自动补全
如果 @keyframes 里没写 0% 或 100%,浏览器不会报错,而是用元素自身的计算样式来填充。这个特性有时很方便,有时会踩坑。
比如元素本身有 opacity: 1,你只写了 50% { opacity: 0; },浏览器会自动补全 0% { opacity: 1; } 和 100% { opacity: 1; }。动画效果就是先从不透明渐变到透明,再从透明渐变回不透明。
但如果元素的样式在动画过程中被其它规则改了,自动补全的值也会跟着变,动画效果就不稳定了。所以一般建议显式写出 0% 和 100%。
同名 @keyframes 和重复百分比的覆盖规则
如果样式表里出现了两个同名的 @keyframes 规则,后面的整个替换前面的,不是合并。
在同一个 @keyframes 里,同一个百分比出现多次的话,后面的声明覆盖前面的。这和普通 CSS 的层叠规则一致。
@keyframes fade {
from { opacity: 0; }
to { opacity: 1; }
}
/* 这个会完全替换上面那个 */
@keyframes fade {
from { opacity: 0.5; }
to { opacity: 1; }
}引入第三方动画库时容易遇到这个问题。如果你定义的 @keyframes 和库里的同名,一个会覆盖另一个,动画就不对了。给自己的关键帧加命名前缀可以避免冲突。
容易答错的地方
- 以为省略
0%动画就从当前位置开始 - 省略
0%时浏览器确实用元素当前样式补全,但「当前样式」是计算后的值,不一定是你直觉上想的值。如果元素的样式受到其它动画、伪类或媒体查询的影响,补全的值可能不是预期的。显式写出0%更安全。 - 以为百分比可以超出 0~100 的范围
@keyframes里的百分比只能在 0% 到 100% 之间,负数或超过 100% 的值会被忽略。这一点和cubic-bezier的控制点不同,贝塞尔曲线的 y 值可以超出 0~1 范围来实现弹性效果。
面试官还会怎么问?
@keyframes 里能写 !important 吗?
不能。@keyframes 里的声明会忽略 !important,写了也没效果。动画本身在层叠中已经有很高的优先级,不需要也不支持 !important。
只有一帧的 @keyframes 会怎么样?
如果只写了 to 没写 from,浏览器用元素当前样式补全 from,动画正常播放。如果只写了 from 没写 to,同理补全 to。如果整个 @keyframes 只有一个百分比,比如只有 50%,浏览器会补全 0% 和 100%,动画也能播。
关键帧里写 animation 属性会怎样?
@keyframes 里不能设置 animation-* 系列属性,写了会被忽略。关键帧只负责描述样式变化,动画的播放行为(时长、延迟、方向等)由元素上的 animation 属性控制。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。