cubic-bezier() 仅定义时间到进度的映射,不能生成二维贝塞尔轨迹;真正实现需用 offset-path + offset-distance 或 javascript 手动插值计算坐标。

cubic-bezier() 本身不能让元素沿二维贝塞尔路径移动,它只控制属性变化的速度曲线。真正在平面上画出曲线轨迹,必须用 offset-path + offset-distance,或者退而求其次用 JavaScript 动态计算坐标。
为什么 cubic-bezier(0.25, 0.1, 0.25, 1) 不会让元素“走曲线”?
这是最常被误解的一点:cubic-bezier() 描述的是「时间 → 进度」映射关系,不是「时间 → 坐标」。比如你写 transition: left 1s cubic-bezier(...); top 1s cubic-bezier(...);,两个方向各自按自己的缓动函数线性插值,结果是矩形区域内的某种斜线或折线运动,不是数学意义上的贝塞尔轨迹。
- 它只能影响单个 CSS 属性(如
left、opacity)随时间变化的节奏 - 无法耦合
x和y的计算逻辑,因此无法生成真正弯曲的空间路径 - 强行用多段
transform: translate()拼接,会因采样率低、关键帧密度不足导致抖动或失真
offset-path 是目前唯一原生 CSS 解法,但有硬性前提
要让元素沿 path("M0,0 C50,100 150,-50 200,0") 这类三次贝塞尔路径运动,必须同时满足:
-
position必须是absolute或fixed——relative、static、sticky下该声明直接被浏览器忽略,且不报错 - 路径字符串必须是单行、无单位、无空格、大小写严格匹配:✅
path("M0,0C50,100,150,-50,200,0"),❌path("M 0, 0 C 50, 100, 150, -50, 200, 0") - 必须显式设置
offset-distance动画(用@keyframes或transition),否则路径加载但不动 - Safari 要求路径中所有字母大写(
M、C),Chrome/Firefox 容错稍好但建议统一用大写
兼容性差时,JavaScript 是更可控的 fallback 方案
当需要支持 Firefox 旧版、IE 或部分安卓 WebView 时,Canvas 或 SVG + requestAnimationFrame 是实际选择。核心是手动实现三次贝塞尔插值:
function bezier(t, p0, p1, p2, p3) {
const u = 1 - t;
return u*u*u*p0 + 3*u*u*t*p1 + 3*u*t*t*p2 + t*t*t*p3;
}
<p>// 给定四个点,算出 t∈[0,1] 时的 (x,y)
const x = bezier(t, 0, 50, 150, 200);
const y = bezier(t, 0, 100, -50, 0);
el.style.transform = <code>translate(${x}px, ${y}px)</code>;</p>
- 用
requestAnimationFrame控制t从 0 到 1 的推进节奏,比 CSStransition更灵活 - 可结合
cubic-bezier()控制t的变化速度,实现“路径+缓动”双重定制 - 注意避免在循环中频繁读写
offsetLeft等触发重排的属性;优先用transform和will-change: transform
真正难的不是写出路径,而是确保路径坐标系与容器布局对齐、处理缩放/滚动下的偏移漂移、以及在 Safari 中那个连多一个空格都会静默失败的 offset-path 字符串。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











