纯CSS无法精确实现抛物线动画,因其@keyframes仅支持线性、缓动或分段关键帧,无法描述二次函数轨迹;推荐JS计算坐标+CSS硬件加速方案,或用两段cubic-bezier近似模拟。

用 animate() + CSS transform 模拟抛物线最可行
Bootstrap 本身不提供抛物线动画能力,animate()(jQuery)或 Element.animate()(Web Animations API)才是实际执行者。Bootstrap 的作用仅限于快速搭建购物车 UI 结构和响应式布局,动画得自己补。
直接用 CSS @keyframes 写固定路径会僵硬——商品位置不同,抛物线起点、终点、弧度都该动态算。所以必须用 JS 实时计算贝塞尔曲线控制点或分段位移。
- 推荐用
Element.animate()配合cubic-bezier(0.2, 0.8, 0.4, 1):它比线性更自然,且浏览器硬件加速支持好 - 避免用
top/left定位做动画:触发重排,卡顿明显;一律改用transform: translate(x, y) - 起点取商品卡片的
getBoundingClientRect(),终点取购物车图标位置,两者中心对齐更准
如何获取准确的起点和终点坐标
用户点击“加入购物车”按钮时,商品卡片可能在滚动区域中,也可能被 position: sticky 或 transform 影响,直接读 offsetTop 会错。
必须用 getBoundingClientRect() 并转换为视口坐标,再通过 document.documentElement.scrollTop 和页面缩放校正:
const cartIcon = document.querySelector('.navbar-cart');
const iconRect = cartIcon.getBoundingClientRect();
const targetX = iconRect.left + iconRect.width / 2;
const targetY = iconRect.top + iconRect.height / 2;
const itemRect = itemEl.getBoundingClientRect();
const startX = itemRect.left + itemRect.width / 2;
const startY = itemRect.top + itemRect.height / 2;
- 别忘了考虑
window.devicePixelRatio对高 DPI 屏幕的影响(一般可忽略,但金融/设计类项目建议校正) - 如果购物车图标在
fixed导航栏里,targetY不受滚动影响;但商品在overflow-y: auto区域内时,startY必须加window.scrollY
为什么不用 Bootstrap 的 fade 或 slide 类
Bootstrap 的 fade、slide 等过渡类只支持预设的简单动效,且绑定在 show/hide 类上,无法控制运动轨迹或中途暂停。
-
fade是透明度变化,不是位移;slide只沿 Y 轴线性滑动,不符合抛物线需求 - 这些类依赖
transition,而transition无法响应 JS 动态计算的多关键帧路径 - 强行覆盖
.slide-in-down的transform值会导致动画打架,Chrome DevTools 里能看到transition被 cancel
移动端点击后动画突然偏移或消失
常见原因是 Safari/iOS WebView 对 transform: translateZ(0) 或 will-change 的处理差异,或点击穿透导致元素被意外移除。
- 确保动画元素在触发前已挂载到 DOM,不要在
click回调里先remove()再动画 - 给飞入中的元素加
pointer-events: none,防止动画期间误触其他按钮 - iOS 上若用
position: fixed导航栏,需在动画结束时手动scrollTo(0, 0)修复视觉错位(Safari 滚动锚定 bug) - 测试时关掉「减少动画」系统设置,否则
prefers-reduced-motion会禁用所有transform动画
抛物线不是纯数学题,而是视觉预期管理:人眼对起始加速度和落地缓冲更敏感,控制点选在 0.2–0.4 区间比严格按物理公式更可靠。坐标算错一像素,动画就显得“飘”,所以务必用 getBoundingClientRect() 而非估测值。


















