css的cubic-bezier()仅控制动画时间节奏,无法实现贝塞尔路径运动;真要沿曲线轨迹移动,需用svg的、css的offset-path(safari 15.4+支持)或canvas手动插值计算。

直接用 cubic-bezier() 做动画,只能控制「时间节奏」,不能让元素「沿贝塞尔路径移动」——这是最常被混淆的点。真要走曲线轨迹,得换方案。
css cubic-bezier() 只调速,不调路
cubic-bezier() 是 CSS 动画的 animation-timing-function,它只影响属性值随时间变化的快慢(比如 transform: translateX() 怎么动),不改变运动的几何路径本身。哪怕你写 cubic-bezier(0.5, -800, 0.5, 800),元素也还是直线来回跑,只是加速度极端夸张而已。
常见错误现象:
- 以为调了
cubic-bezier()就能让小球画弧线,结果发现只是“忽快忽慢地横着抖” - 用
@property+ 自定义变量模拟二维位移,但两个轴独立插值,合成后轨迹仍是折线或椭圆,不是贝塞尔曲线
真正能表达路径的 CSS 属性只有 offset-path(配合 offset-distance),但它在 Safari 15.4+ 才稳定支持,且不兼容 IE 和旧版 Android WebView。
svg 是最稳的原生解法
SVG 的 <animatemotion></animatemotion> 直接支持三次贝塞尔路径,无需 JS,浏览器原生解析 d 指令,性能好、可暂停、可 reverse,还支持 keyPoints + keyTimes 控制非线性进度。
关键实操点:
- 路径必须写在
<path d="M0,0 C50,100 150,100 200,0"></path>里,C后面六个数字:两个控制点 + 终点 - 要动的元素得包在
<g></g>里,并设transform="translate(0,0)",否则起点偏移难对齐 - 如果想让圆形“底部贴路径”(比如模拟车轮),得提前加
transform="translate(0,6)"把圆心下移半径 -
keyPoints="0;0.3;1"和keyTimes="0;0.5;1"必须等长,且每个值 ∈ [0,1]
示例片段:
<svg width="300" height="150"><path id="motionPath" d="M20,80 C50,20 150,20 180,80" fill="none" stroke="#ccc"></path><g><circle r="6" fill="#3498db"></circle><animatemotion dur="3s" repeatcount="indefinite"><mpath href="https://www.php.cn/link/75386da74404e906cdb7acbf5e3ef18b"></mpath></animatemotion></g></svg>
canvas 手动算点适合精细控制
当你要实时采集轨迹、叠加物理效果(比如阻尼、碰撞)、或做粒子系统时,canvas 是更灵活的选择。核心是自己实现贝塞尔方程,逐帧算出坐标再绘制。
注意差异:
- 二次贝塞尔用
quadraticCurveTo(cpx, cpy, x, y),只需一个控制点 - 三次贝塞尔用
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y),需要两个控制点 - 动画主循环里别直接用
t += 0.01硬递增,应基于requestAnimationFrame时间戳计算t,避免帧率波动导致速度不均 - 若要画轨迹线,把历史点存进数组(如
points.push({x, y})),每帧重绘整条线;想省性能就只画最近 N 段
简易三次贝塞尔插值函数:
function cubicBezier(p0, p1, p2, p3, t) {
const k = 1 - t;
return k**3 * p0 +
3 * k**2 * t * p1 +
3 * k * t**2 * p2 +
t**3 * p3;
}
别踩 canvas 贝塞尔的精度坑
canvas 的 bezierCurveTo() 是渲染 API,它把整条曲线光栅化成像素,不暴露中间点。你想获取某时刻的位置?不行。想中途暂停并拖拽控制点?得自己重写插值逻辑。
容易被忽略的点:
- 用
quadraticCurveTo()时,起始点是当前 path 的终点,不是画布原点——忘了moveTo()就会连到 (0,0) - 控制点坐标是绝对位置,不是相对偏移,别误当成 CSS 的
transform那样理解 - 高阶贝塞尔(四阶以上)canvas 不支持,强行拟合要用分段三次逼近,别硬刚
真要动态调参看效果,建议先用 SVG + DevTools 实时改 d 属性,确认路径形状后再迁移到 canvas 计算逻辑里。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











