ease不是纯“先慢后快”,而是“慢–快–慢”;要实现严格先慢后快,应使用ease-in或cubic-bezier(0.25,0.1,0.75,0.9)等自定义曲线。

ease 就是默认的「先慢后快再慢」,不是你要的纯「先慢后快」。真要实现严格意义上的先慢后快(无减速尾段),得用 cubic-bezier(0.25, 0.1, 0.75, 0.9) 这类自定义曲线,或者选 ease-in —— 它只缓入、不缓出。
为什么 ease 不等于「先慢后快」?
ease 实际是 cubic-bezier(0.25, 0.1, 0.25, 1),它有三个阶段:起始缓入 → 中段加速 → 结尾缓出。视觉上是“慢–快–慢”,适合按钮反馈这类需要收住的动作。如果你想要的是“慢→快→直接停”,比如模拟重力下落或加速入场,ease 的结尾减速会破坏节奏感。
用 ease-in 最简实现「先慢后快」
这是最直接、兼容性最好的方案,无需记忆贝塞尔参数:
-
ease-in表示从速度为 0 开始,持续加速到结束,没有减速段 - 适用于元素入场、展开动画、图标放大等强调“启动感”的场景
- 注意:它对人眼来说可能显得“戛然而止”,建议搭配略长的
transition-duration(如0.4s)缓解生硬感
示例:
.card {
opacity: 0;
transform: translateY(20px);
transition: opacity 0.4s ease-in, transform 0.4s ease-in;
}
.card.show {
opacity: 1;
transform: translateY(0);
}
用 cubic-bezier() 精准控制加速度曲线
如果 ease-in 还不够——比如你想在 70% 进度前都保持低速,之后陡然加速——就得手调贝塞尔函数:
立即学习“前端免费学习笔记(深入)”;
- 第一个控制点
(x1, y1)决定起始斜率(越小越慢),第二个(x2, y2)决定结束斜率(y2 越大,结尾越快) - 想强化“先慢后快”,把
y1设得很低(如0.05),y2设得很高(如0.95),x 值保持常规(0.25和0.75) - 推荐调试工具:cubic-bezier.com,拖动锚点实时预览
例如:transition-timing-function: cubic-bezier(0.25, 0.05, 0.75, 0.95);
容易被忽略的触发与属性限制
即使 timing function 写对了,过渡也可能不生效:
- 没写
transition-duration—— 默认值是0s,等于没动画 - 过渡的属性不支持插值,比如
display、height: auto、font-family,这些写上去毫无反应 - 用 JS 直接改
style时,若旧值未被浏览器计算(如刚插入 DOM 就设新样式),过渡可能跳过,需强制 reflow:element.offsetHeight; - 多个属性共用一个 timing function 时,简写顺序必须和
transition-property一一对应,否则错位
真正难的不是写出「先慢后快」,而是确保它在各种触发路径(:hover / class 切换 / JS 动态注入)下都稳定生效。timing function 只是其中一环,别让它掩盖了 duration 缺失或属性不可动画这些更底层的问题。



















